home *** CD-ROM | disk | FTP | other *** search
/ PC go! 2017 October / PCgo 10-2017 CD-ROM Germany.iso / nw.pak / Unnamed File 000214.txt < prev    next >
Encoding:
Text File  |  2015-07-29  |  335.7 KB  |  11,850 lines

  1. /**
  2.  * @license
  3.  * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
  4.  * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
  5.  * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
  6.  * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
  7.  * Code distributed by Google as part of the polymer project is also
  8.  * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
  9.  */
  10. // @version 0.5.1
  11. window.PolymerGestures = {};
  12.  
  13. (function(scope) {
  14.   var HAS_FULL_PATH = false;
  15.  
  16.   // test for full event path support
  17.   var pathTest = document.createElement('meta');
  18.   if (pathTest.createShadowRoot) {
  19.     var sr = pathTest.createShadowRoot();
  20.     var s = document.createElement('span');
  21.     sr.appendChild(s);
  22.     pathTest.addEventListener('testpath', function(ev) {
  23.       if (ev.path) {
  24.         // if the span is in the event path, then path[0] is the real source for all events
  25.         HAS_FULL_PATH = ev.path[0] === s;
  26.       }
  27.       ev.stopPropagation();
  28.     });
  29.     var ev = new CustomEvent('testpath', {bubbles: true});
  30.     // must add node to DOM to trigger event listener
  31.     document.head.appendChild(pathTest);
  32.     s.dispatchEvent(ev);
  33.     pathTest.parentNode.removeChild(pathTest);
  34.     sr = s = null;
  35.   }
  36.   pathTest = null;
  37.  
  38.   var target = {
  39.     shadow: function(inEl) {
  40.       if (inEl) {
  41.         return inEl.shadowRoot || inEl.webkitShadowRoot;
  42.       }
  43.     },
  44.     canTarget: function(shadow) {
  45.       return shadow && Boolean(shadow.elementFromPoint);
  46.     },
  47.     targetingShadow: function(inEl) {
  48.       var s = this.shadow(inEl);
  49.       if (this.canTarget(s)) {
  50.         return s;
  51.       }
  52.     },
  53.     olderShadow: function(shadow) {
  54.       var os = shadow.olderShadowRoot;
  55.       if (!os) {
  56.         var se = shadow.querySelector('shadow');
  57.         if (se) {
  58.           os = se.olderShadowRoot;
  59.         }
  60.       }
  61.       return os;
  62.     },
  63.     allShadows: function(element) {
  64.       var shadows = [], s = this.shadow(element);
  65.       while(s) {
  66.         shadows.push(s);
  67.         s = this.olderShadow(s);
  68.       }
  69.       return shadows;
  70.     },
  71.     searchRoot: function(inRoot, x, y) {
  72.       var t, st, sr, os;
  73.       if (inRoot) {
  74.         t = inRoot.elementFromPoint(x, y);
  75.         if (t) {
  76.           // found element, check if it has a ShadowRoot
  77.           sr = this.targetingShadow(t);
  78.         } else if (inRoot !== document) {
  79.           // check for sibling roots
  80.           sr = this.olderShadow(inRoot);
  81.         }
  82.         // search other roots, fall back to light dom element
  83.         return this.searchRoot(sr, x, y) || t;
  84.       }
  85.     },
  86.     owner: function(element) {
  87.       if (!element) {
  88.         return document;
  89.       }
  90.       var s = element;
  91.       // walk up until you hit the shadow root or document
  92.       while (s.parentNode) {
  93.         s = s.parentNode;
  94.       }
  95.       // the owner element is expected to be a Document or ShadowRoot
  96.       if (s.nodeType != Node.DOCUMENT_NODE && s.nodeType != Node.DOCUMENT_FRAGMENT_NODE) {
  97.         s = document;
  98.       }
  99.       return s;
  100.     },
  101.     findTarget: function(inEvent) {
  102.       if (HAS_FULL_PATH && inEvent.path && inEvent.path.length) {
  103.         return inEvent.path[0];
  104.       }
  105.       var x = inEvent.clientX, y = inEvent.clientY;
  106.       // if the listener is in the shadow root, it is much faster to start there
  107.       var s = this.owner(inEvent.target);
  108.       // if x, y is not in this root, fall back to document search
  109.       if (!s.elementFromPoint(x, y)) {
  110.         s = document;
  111.       }
  112.       return this.searchRoot(s, x, y);
  113.     },
  114.     findTouchAction: function(inEvent) {
  115.       var n;
  116.       if (HAS_FULL_PATH && inEvent.path && inEvent.path.length) {
  117.         var path = inEvent.path;
  118.         for (var i = 0; i < path.length; i++) {
  119.           n = path[i];
  120.           if (n.nodeType === Node.ELEMENT_NODE && n.hasAttribute('touch-action')) {
  121.             return n.getAttribute('touch-action');
  122.           }
  123.         }
  124.       } else {
  125.         n = inEvent.target;
  126.         while(n) {
  127.           if (n.nodeType === Node.ELEMENT_NODE && n.hasAttribute('touch-action')) {
  128.             return n.getAttribute('touch-action');
  129.           }
  130.           n = n.parentNode || n.host;
  131.         }
  132.       }
  133.       // auto is default
  134.       return "auto";
  135.     },
  136.     LCA: function(a, b) {
  137.       if (a === b) {
  138.         return a;
  139.       }
  140.       if (a && !b) {
  141.         return a;
  142.       }
  143.       if (b && !a) {
  144.         return b;
  145.       }
  146.       if (!b && !a) {
  147.         return document;
  148.       }
  149.       // fast case, a is a direct descendant of b or vice versa
  150.       if (a.contains && a.contains(b)) {
  151.         return a;
  152.       }
  153.       if (b.contains && b.contains(a)) {
  154.         return b;
  155.       }
  156.       var adepth = this.depth(a);
  157.       var bdepth = this.depth(b);
  158.       var d = adepth - bdepth;
  159.       if (d >= 0) {
  160.         a = this.walk(a, d);
  161.       } else {
  162.         b = this.walk(b, -d);
  163.       }
  164.       while (a && b && a !== b) {
  165.         a = a.parentNode || a.host;
  166.         b = b.parentNode || b.host;
  167.       }
  168.       return a;
  169.     },
  170.     walk: function(n, u) {
  171.       for (var i = 0; n && (i < u); i++) {
  172.         n = n.parentNode || n.host;
  173.       }
  174.       return n;
  175.     },
  176.     depth: function(n) {
  177.       var d = 0;
  178.       while(n) {
  179.         d++;
  180.         n = n.parentNode || n.host;
  181.       }
  182.       return d;
  183.     },
  184.     deepContains: function(a, b) {
  185.       var common = this.LCA(a, b);
  186.       // if a is the common ancestor, it must "deeply" contain b
  187.       return common === a;
  188.     },
  189.     insideNode: function(node, x, y) {
  190.       var rect = node.getBoundingClientRect();
  191.       return (rect.left <= x) && (x <= rect.right) && (rect.top <= y) && (y <= rect.bottom);
  192.     },
  193.     path: function(event) {
  194.       var p;
  195.       if (HAS_FULL_PATH && event.path && event.path.length) {
  196.         p = event.path;
  197.       } else {
  198.         p = [];
  199.         var n = this.findTarget(event);
  200.         while (n) {
  201.           p.push(n);
  202.           n = n.parentNode || n.host;
  203.         }
  204.       }
  205.       return p;
  206.     }
  207.   };
  208.   scope.targetFinding = target;
  209.   /**
  210.    * Given an event, finds the "deepest" node that could have been the original target before ShadowDOM retargetting
  211.    *
  212.    * @param {Event} Event An event object with clientX and clientY properties
  213.    * @return {Element} The probable event origninator
  214.    */
  215.   scope.findTarget = target.findTarget.bind(target);
  216.   /**
  217.    * Determines if the "container" node deeply contains the "containee" node, including situations where the "containee" is contained by one or more ShadowDOM
  218.    * roots.
  219.    *
  220.    * @param {Node} container
  221.    * @param {Node} containee
  222.    * @return {Boolean}
  223.    */
  224.   scope.deepContains = target.deepContains.bind(target);
  225.  
  226.   /**
  227.    * Determines if the x/y position is inside the given node.
  228.    *
  229.    * Example:
  230.    *
  231.    *     function upHandler(event) {
  232.    *       var innode = PolymerGestures.insideNode(event.target, event.clientX, event.clientY);
  233.    *       if (innode) {
  234.    *         // wait for tap?
  235.    *       } else {
  236.    *         // tap will never happen
  237.    *       }
  238.    *     }
  239.    *
  240.    * @param {Node} node
  241.    * @param {Number} x Screen X position
  242.    * @param {Number} y screen Y position
  243.    * @return {Boolean}
  244.    */
  245.   scope.insideNode = target.insideNode;
  246.  
  247. })(window.PolymerGestures);
  248.  
  249. (function() {
  250.   function shadowSelector(v) {
  251.     return 'html /deep/ ' + selector(v);
  252.   }
  253.   function selector(v) {
  254.     return '[touch-action="' + v + '"]';
  255.   }
  256.   function rule(v) {
  257.     return '{ -ms-touch-action: ' + v + '; touch-action: ' + v + ';}';
  258.   }
  259.   var attrib2css = [
  260.     'none',
  261.     'auto',
  262.     'pan-x',
  263.     'pan-y',
  264.     {
  265.       rule: 'pan-x pan-y',
  266.       selectors: [
  267.         'pan-x pan-y',
  268.         'pan-y pan-x'
  269.       ]
  270.     },
  271.     'manipulation'
  272.   ];
  273.   var styles = '';
  274.   // only install stylesheet if the browser has touch action support
  275.   var hasTouchAction = typeof document.head.style.touchAction === 'string';
  276.   // only add shadow selectors if shadowdom is supported
  277.   var hasShadowRoot = !window.ShadowDOMPolyfill && document.head.createShadowRoot;
  278.  
  279.   if (hasTouchAction) {
  280.     attrib2css.forEach(function(r) {
  281.       if (String(r) === r) {
  282.         styles += selector(r) + rule(r) + '\n';
  283.         if (hasShadowRoot) {
  284.           styles += shadowSelector(r) + rule(r) + '\n';
  285.         }
  286.       } else {
  287.         styles += r.selectors.map(selector) + rule(r.rule) + '\n';
  288.         if (hasShadowRoot) {
  289.           styles += r.selectors.map(shadowSelector) + rule(r.rule) + '\n';
  290.         }
  291.       }
  292.     });
  293.  
  294.     var el = document.createElement('style');
  295.     el.textContent = styles;
  296.     document.head.appendChild(el);
  297.   }
  298. })();
  299.  
  300. /**
  301.  * This is the constructor for new PointerEvents.
  302.  *
  303.  * New Pointer Events must be given a type, and an optional dictionary of
  304.  * initialization properties.
  305.  *
  306.  * Due to certain platform requirements, events returned from the constructor
  307.  * identify as MouseEvents.
  308.  *
  309.  * @constructor
  310.  * @param {String} inType The type of the event to create.
  311.  * @param {Object} [inDict] An optional dictionary of initial event properties.
  312.  * @return {Event} A new PointerEvent of type `inType` and initialized with properties from `inDict`.
  313.  */
  314. (function(scope) {
  315.  
  316.   var MOUSE_PROPS = [
  317.     'bubbles',
  318.     'cancelable',
  319.     'view',
  320.     'detail',
  321.     'screenX',
  322.     'screenY',
  323.     'clientX',
  324.     'clientY',
  325.     'ctrlKey',
  326.     'altKey',
  327.     'shiftKey',
  328.     'metaKey',
  329.     'button',
  330.     'relatedTarget',
  331.     'pageX',
  332.     'pageY'
  333.   ];
  334.  
  335.   var MOUSE_DEFAULTS = [
  336.     false,
  337.     false,
  338.     null,
  339.     null,
  340.     0,
  341.     0,
  342.     0,
  343.     0,
  344.     false,
  345.     false,
  346.     false,
  347.     false,
  348.     0,
  349.     null,
  350.     0,
  351.     0
  352.   ];
  353.  
  354.   var NOP_FACTORY = function(){ return function(){}; };
  355.  
  356.   var eventFactory = {
  357.     // TODO(dfreedm): this is overridden by tap recognizer, needs review
  358.     preventTap: NOP_FACTORY,
  359.     makeBaseEvent: function(inType, inDict) {
  360.       var e = document.createEvent('Event');
  361.       e.initEvent(inType, inDict.bubbles || false, inDict.cancelable || false);
  362.       e.preventTap = eventFactory.preventTap(e);
  363.       return e;
  364.     },
  365.     makeGestureEvent: function(inType, inDict) {
  366.       inDict = inDict || Object.create(null);
  367.  
  368.       var e = this.makeBaseEvent(inType, inDict);
  369.       for (var i = 0, keys = Object.keys(inDict), k; i < keys.length; i++) {
  370.         k = keys[i];
  371.         e[k] = inDict[k];
  372.       }
  373.       return e;
  374.     },
  375.     makePointerEvent: function(inType, inDict) {
  376.       inDict = inDict || Object.create(null);
  377.  
  378.       var e = this.makeBaseEvent(inType, inDict);
  379.       // define inherited MouseEvent properties
  380.       for(var i = 0, p; i < MOUSE_PROPS.length; i++) {
  381.         p = MOUSE_PROPS[i];
  382.         e[p] = inDict[p] || MOUSE_DEFAULTS[i];
  383.       }
  384.       e.buttons = inDict.buttons || 0;
  385.  
  386.       // Spec requires that pointers without pressure specified use 0.5 for down
  387.       // state and 0 for up state.
  388.       var pressure = 0;
  389.       if (inDict.pressure) {
  390.         pressure = inDict.pressure;
  391.       } else {
  392.         pressure = e.buttons ? 0.5 : 0;
  393.       }
  394.  
  395.       // add x/y properties aliased to clientX/Y
  396.       e.x = e.clientX;
  397.       e.y = e.clientY;
  398.  
  399.       // define the properties of the PointerEvent interface
  400.       e.pointerId = inDict.pointerId || 0;
  401.       e.width = inDict.width || 0;
  402.       e.height = inDict.height || 0;
  403.       e.pressure = pressure;
  404.       e.tiltX = inDict.tiltX || 0;
  405.       e.tiltY = inDict.tiltY || 0;
  406.       e.pointerType = inDict.pointerType || '';
  407.       e.hwTimestamp = inDict.hwTimestamp || 0;
  408.       e.isPrimary = inDict.isPrimary || false;
  409.       e._source = inDict._source || '';
  410.       return e;
  411.     }
  412.   };
  413.  
  414.   scope.eventFactory = eventFactory;
  415. })(window.PolymerGestures);
  416.  
  417. /**
  418.  * This module implements an map of pointer states
  419.  */
  420. (function(scope) {
  421.   var USE_MAP = window.Map && window.Map.prototype.forEach;
  422.   var POINTERS_FN = function(){ return this.size; };
  423.   function PointerMap() {
  424.     if (USE_MAP) {
  425.       var m = new Map();
  426.       m.pointers = POINTERS_FN;
  427.       return m;
  428.     } else {
  429.       this.keys = [];
  430.       this.values = [];
  431.     }
  432.   }
  433.  
  434.   PointerMap.prototype = {
  435.     set: function(inId, inEvent) {
  436.       var i = this.keys.indexOf(inId);
  437.       if (i > -1) {
  438.         this.values[i] = inEvent;
  439.       } else {
  440.         this.keys.push(inId);
  441.         this.values.push(inEvent);
  442.       }
  443.     },
  444.     has: function(inId) {
  445.       return this.keys.indexOf(inId) > -1;
  446.     },
  447.     'delete': function(inId) {
  448.       var i = this.keys.indexOf(inId);
  449.       if (i > -1) {
  450.         this.keys.splice(i, 1);
  451.         this.values.splice(i, 1);
  452.       }
  453.     },
  454.     get: function(inId) {
  455.       var i = this.keys.indexOf(inId);
  456.       return this.values[i];
  457.     },
  458.     clear: function() {
  459.       this.keys.length = 0;
  460.       this.values.length = 0;
  461.     },
  462.     // return value, key, map
  463.     forEach: function(callback, thisArg) {
  464.       this.values.forEach(function(v, i) {
  465.         callback.call(thisArg, v, this.keys[i], this);
  466.       }, this);
  467.     },
  468.     pointers: function() {
  469.       return this.keys.length;
  470.     }
  471.   };
  472.  
  473.   scope.PointerMap = PointerMap;
  474. })(window.PolymerGestures);
  475.  
  476. (function(scope) {
  477.   var CLONE_PROPS = [
  478.     // MouseEvent
  479.     'bubbles',
  480.     'cancelable',
  481.     'view',
  482.     'detail',
  483.     'screenX',
  484.     'screenY',
  485.     'clientX',
  486.     'clientY',
  487.     'ctrlKey',
  488.     'altKey',
  489.     'shiftKey',
  490.     'metaKey',
  491.     'button',
  492.     'relatedTarget',
  493.     // DOM Level 3
  494.     'buttons',
  495.     // PointerEvent
  496.     'pointerId',
  497.     'width',
  498.     'height',
  499.     'pressure',
  500.     'tiltX',
  501.     'tiltY',
  502.     'pointerType',
  503.     'hwTimestamp',
  504.     'isPrimary',
  505.     // event instance
  506.     'type',
  507.     'target',
  508.     'currentTarget',
  509.     'which',
  510.     'pageX',
  511.     'pageY',
  512.     'timeStamp',
  513.     // gesture addons
  514.     'preventTap',
  515.     'tapPrevented',
  516.     '_source'
  517.   ];
  518.  
  519.   var CLONE_DEFAULTS = [
  520.     // MouseEvent
  521.     false,
  522.     false,
  523.     null,
  524.     null,
  525.     0,
  526.     0,
  527.     0,
  528.     0,
  529.     false,
  530.     false,
  531.     false,
  532.     false,
  533.     0,
  534.     null,
  535.     // DOM Level 3
  536.     0,
  537.     // PointerEvent
  538.     0,
  539.     0,
  540.     0,
  541.     0,
  542.     0,
  543.     0,
  544.     '',
  545.     0,
  546.     false,
  547.     // event instance
  548.     '',
  549.     null,
  550.     null,
  551.     0,
  552.     0,
  553.     0,
  554.     0,
  555.     function(){},
  556.     false
  557.   ];
  558.  
  559.   var HAS_SVG_INSTANCE = (typeof SVGElementInstance !== 'undefined');
  560.  
  561.   var eventFactory = scope.eventFactory;
  562.  
  563.   // set of recognizers to run for the currently handled event
  564.   var currentGestures;
  565.  
  566.   /**
  567.    * This module is for normalizing events. Mouse and Touch events will be
  568.    * collected here, and fire PointerEvents that have the same semantics, no
  569.    * matter the source.
  570.    * Events fired:
  571.    *   - pointerdown: a pointing is added
  572.    *   - pointerup: a pointer is removed
  573.    *   - pointermove: a pointer is moved
  574.    *   - pointerover: a pointer crosses into an element
  575.    *   - pointerout: a pointer leaves an element
  576.    *   - pointercancel: a pointer will no longer generate events
  577.    */
  578.   var dispatcher = {
  579.     IS_IOS: false,
  580.     pointermap: new scope.PointerMap(),
  581.     requiredGestures: new scope.PointerMap(),
  582.     eventMap: Object.create(null),
  583.     // Scope objects for native events.
  584.     // This exists for ease of testing.
  585.     eventSources: Object.create(null),
  586.     eventSourceList: [],
  587.     gestures: [],
  588.     // map gesture event -> {listeners: int, index: gestures[int]}
  589.     dependencyMap: {
  590.       // make sure down and up are in the map to trigger "register"
  591.       down: {listeners: 0, index: -1},
  592.       up: {listeners: 0, index: -1}
  593.     },
  594.     gestureQueue: [],
  595.     /**
  596.      * Add a new event source that will generate pointer events.
  597.      *
  598.      * `inSource` must contain an array of event names named `events`, and
  599.      * functions with the names specified in the `events` array.
  600.      * @param {string} name A name for the event source
  601.      * @param {Object} source A new source of platform events.
  602.      */
  603.     registerSource: function(name, source) {
  604.       var s = source;
  605.       var newEvents = s.events;
  606.       if (newEvents) {
  607.         newEvents.forEach(function(e) {
  608.           if (s[e]) {
  609.             this.eventMap[e] = s[e].bind(s);
  610.           }
  611.         }, this);
  612.         this.eventSources[name] = s;
  613.         this.eventSourceList.push(s);
  614.       }
  615.     },
  616.     registerGesture: function(name, source) {
  617.       var obj = Object.create(null);
  618.       obj.listeners = 0;
  619.       obj.index = this.gestures.length;
  620.       for (var i = 0, g; i < source.exposes.length; i++) {
  621.         g = source.exposes[i].toLowerCase();
  622.         this.dependencyMap[g] = obj;
  623.       }
  624.       this.gestures.push(source);
  625.     },
  626.     register: function(element, initial) {
  627.       var l = this.eventSourceList.length;
  628.       for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) {
  629.         // call eventsource register
  630.         es.register.call(es, element, initial);
  631.       }
  632.     },
  633.     unregister: function(element) {
  634.       var l = this.eventSourceList.length;
  635.       for (var i = 0, es; (i < l) && (es = this.eventSourceList[i]); i++) {
  636.         // call eventsource register
  637.         es.unregister.call(es, element);
  638.       }
  639.     },
  640.     // EVENTS
  641.     down: function(inEvent) {
  642.       this.requiredGestures.set(inEvent.pointerId, currentGestures);
  643.       this.fireEvent('down', inEvent);
  644.     },
  645.     move: function(inEvent) {
  646.       // pipe move events into gesture queue directly
  647.       inEvent.type = 'move';
  648.       this.fillGestureQueue(inEvent);
  649.     },
  650.     up: function(inEvent) {
  651.       this.fireEvent('up', inEvent);
  652.       this.requiredGestures.delete(inEvent.pointerId);
  653.     },
  654.     cancel: function(inEvent) {
  655.       inEvent.tapPrevented = true;
  656.       this.fireEvent('up', inEvent);
  657.       this.requiredGestures.delete(inEvent.pointerId);
  658.     },
  659.     addGestureDependency: function(node, currentGestures) {
  660.       var gesturesWanted = node._pgEvents;
  661.       if (gesturesWanted && currentGestures) {
  662.         var gk = Object.keys(gesturesWanted);
  663.         for (var i = 0, r, ri, g; i < gk.length; i++) {
  664.           // gesture
  665.           g = gk[i];
  666.           if (gesturesWanted[g] > 0) {
  667.             // lookup gesture recognizer
  668.             r = this.dependencyMap[g];
  669.             // recognizer index
  670.             ri = r ? r.index : -1;
  671.             currentGestures[ri] = true;
  672.           }
  673.         }
  674.       }
  675.     },
  676.     // LISTENER LOGIC
  677.     eventHandler: function(inEvent) {
  678.       // This is used to prevent multiple dispatch of events from
  679.       // platform events. This can happen when two elements in different scopes
  680.       // are set up to create pointer events, which is relevant to Shadow DOM.
  681.  
  682.       var type = inEvent.type;
  683.  
  684.       // only generate the list of desired events on "down"
  685.       if (type === 'touchstart' || type === 'mousedown' || type === 'pointerdown' || type === 'MSPointerDown') {
  686.         if (!inEvent._handledByPG) {
  687.           currentGestures = {};
  688.         }
  689.  
  690.         // in IOS mode, there is only a listener on the document, so this is not re-entrant
  691.         if (this.IS_IOS) {
  692.           var ev = inEvent;
  693.           if (type === 'touchstart') {
  694.             var ct = inEvent.changedTouches[0];
  695.             // set up a fake event to give to the path builder
  696.             ev = {target: inEvent.target, clientX: ct.clientX, clientY: ct.clientY, path: inEvent.path};
  697.           }
  698.           // use event path if available, otherwise build a path from target finding
  699.           var nodes = inEvent.path || scope.targetFinding.path(ev);
  700.           for (var i = 0, n; i < nodes.length; i++) {
  701.             n = nodes[i];
  702.             this.addGestureDependency(n, currentGestures);
  703.           }
  704.         } else {
  705.           this.addGestureDependency(inEvent.currentTarget, currentGestures);
  706.         }
  707.       }
  708.  
  709.       if (inEvent._handledByPG) {
  710.         return;
  711.       }
  712.       var fn = this.eventMap && this.eventMap[type];
  713.       if (fn) {
  714.         fn(inEvent);
  715.       }
  716.       inEvent._handledByPG = true;
  717.     },
  718.     // set up event listeners
  719.     listen: function(target, events) {
  720.       for (var i = 0, l = events.length, e; (i < l) && (e = events[i]); i++) {
  721.         this.addEvent(target, e);
  722.       }
  723.     },
  724.     // remove event listeners
  725.     unlisten: function(target, events) {
  726.       for (var i = 0, l = events.length, e; (i < l) && (e = events[i]); i++) {
  727.         this.removeEvent(target, e);
  728.       }
  729.     },
  730.     addEvent: function(target, eventName) {
  731.       target.addEventListener(eventName, this.boundHandler);
  732.     },
  733.     removeEvent: function(target, eventName) {
  734.       target.removeEventListener(eventName, this.boundHandler);
  735.     },
  736.     // EVENT CREATION AND TRACKING
  737.     /**
  738.      * Creates a new Event of type `inType`, based on the information in
  739.      * `inEvent`.
  740.      *
  741.      * @param {string} inType A string representing the type of event to create
  742.      * @param {Event} inEvent A platform event with a target
  743.      * @return {Event} A PointerEvent of type `inType`
  744.      */
  745.     makeEvent: function(inType, inEvent) {
  746.       var e = eventFactory.makePointerEvent(inType, inEvent);
  747.       e.preventDefault = inEvent.preventDefault;
  748.       e.tapPrevented = inEvent.tapPrevented;
  749.       e._target = e._target || inEvent.target;
  750.       return e;
  751.     },
  752.     // make and dispatch an event in one call
  753.     fireEvent: function(inType, inEvent) {
  754.       var e = this.makeEvent(inType, inEvent);
  755.       return this.dispatchEvent(e);
  756.     },
  757.     /**
  758.      * Returns a snapshot of inEvent, with writable properties.
  759.      *
  760.      * @param {Event} inEvent An event that contains properties to copy.
  761.      * @return {Object} An object containing shallow copies of `inEvent`'s
  762.      *    properties.
  763.      */
  764.     cloneEvent: function(inEvent) {
  765.       var eventCopy = Object.create(null), p;
  766.       for (var i = 0; i < CLONE_PROPS.length; i++) {
  767.         p = CLONE_PROPS[i];
  768.         eventCopy[p] = inEvent[p] || CLONE_DEFAULTS[i];
  769.         // Work around SVGInstanceElement shadow tree
  770.         // Return the <use> element that is represented by the instance for Safari, Chrome, IE.
  771.         // This is the behavior implemented by Firefox.
  772.         if (p === 'target' || p === 'relatedTarget') {
  773.           if (HAS_SVG_INSTANCE && eventCopy[p] instanceof SVGElementInstance) {
  774.             eventCopy[p] = eventCopy[p].correspondingUseElement;
  775.           }
  776.         }
  777.       }
  778.       // keep the semantics of preventDefault
  779.       eventCopy.preventDefault = function() {
  780.         inEvent.preventDefault();
  781.       };
  782.       return eventCopy;
  783.     },
  784.     /**
  785.      * Dispatches the event to its target.
  786.      *
  787.      * @param {Event} inEvent The event to be dispatched.
  788.      * @return {Boolean} True if an event handler returns true, false otherwise.
  789.      */
  790.     dispatchEvent: function(inEvent) {
  791.       var t = inEvent._target;
  792.       if (t) {
  793.         t.dispatchEvent(inEvent);
  794.         // clone the event for the gesture system to process
  795.         // clone after dispatch to pick up gesture prevention code
  796.         var clone = this.cloneEvent(inEvent);
  797.         clone.target = t;
  798.         this.fillGestureQueue(clone);
  799.       }
  800.     },
  801.     gestureTrigger: function() {
  802.       // process the gesture queue
  803.       for (var i = 0, e, rg; i < this.gestureQueue.length; i++) {
  804.         e = this.gestureQueue[i];
  805.         rg = e._requiredGestures;
  806.         if (rg) {
  807.           for (var j = 0, g, fn; j < this.gestures.length; j++) {
  808.             // only run recognizer if an element in the source event's path is listening for those gestures
  809.             if (rg[j]) {
  810.               g = this.gestures[j];
  811.               fn = g[e.type];
  812.               if (fn) {
  813.                 fn.call(g, e);
  814.               }
  815.             }
  816.           }
  817.         }
  818.       }
  819.       this.gestureQueue.length = 0;
  820.     },
  821.     fillGestureQueue: function(ev) {
  822.       // only trigger the gesture queue once
  823.       if (!this.gestureQueue.length) {
  824.         requestAnimationFrame(this.boundGestureTrigger);
  825.       }
  826.       ev._requiredGestures = this.requiredGestures.get(ev.pointerId);
  827.       this.gestureQueue.push(ev);
  828.     }
  829.   };
  830.   dispatcher.boundHandler = dispatcher.eventHandler.bind(dispatcher);
  831.   dispatcher.boundGestureTrigger = dispatcher.gestureTrigger.bind(dispatcher);
  832.   scope.dispatcher = dispatcher;
  833.  
  834.   /**
  835.    * Listen for `gesture` on `node` with the `handler` function
  836.    *
  837.    * If `handler` is the first listener for `gesture`, the underlying gesture recognizer is then enabled.
  838.    *
  839.    * @param {Element} node
  840.    * @param {string} gesture
  841.    * @return Boolean `gesture` is a valid gesture
  842.    */
  843.   scope.activateGesture = function(node, gesture) {
  844.     var g = gesture.toLowerCase();
  845.     var dep = dispatcher.dependencyMap[g];
  846.     if (dep) {
  847.       var recognizer = dispatcher.gestures[dep.index];
  848.       if (!node._pgListeners) {
  849.         dispatcher.register(node);
  850.         node._pgListeners = 0;
  851.       }
  852.       // TODO(dfreedm): re-evaluate bookkeeping to avoid using attributes
  853.       if (recognizer) {
  854.         var touchAction = recognizer.defaultActions && recognizer.defaultActions[g];
  855.         var actionNode;
  856.         switch(node.nodeType) {
  857.           case Node.ELEMENT_NODE:
  858.             actionNode = node;
  859.           break;
  860.           case Node.DOCUMENT_FRAGMENT_NODE:
  861.             actionNode = node.host;
  862.           break;
  863.           default:
  864.             actionNode = null;
  865.           break;
  866.         }
  867.         if (touchAction && actionNode && !actionNode.hasAttribute('touch-action')) {
  868.           actionNode.setAttribute('touch-action', touchAction);
  869.         }
  870.       }
  871.       if (!node._pgEvents) {
  872.         node._pgEvents = {};
  873.       }
  874.       node._pgEvents[g] = (node._pgEvents[g] || 0) + 1;
  875.       node._pgListeners++;
  876.     }
  877.     return Boolean(dep);
  878.   };
  879.  
  880.   /**
  881.    *
  882.    * Listen for `gesture` from `node` with `handler` function.
  883.    *
  884.    * @param {Element} node
  885.    * @param {string} gesture
  886.    * @param {Function} handler
  887.    * @param {Boolean} capture
  888.    */
  889.   scope.addEventListener = function(node, gesture, handler, capture) {
  890.     if (handler) {
  891.       scope.activateGesture(node, gesture);
  892.       node.addEventListener(gesture, handler, capture);
  893.     }
  894.   };
  895.  
  896.   /**
  897.    * Tears down the gesture configuration for `node`
  898.    *
  899.    * If `handler` is the last listener for `gesture`, the underlying gesture recognizer is disabled.
  900.    *
  901.    * @param {Element} node
  902.    * @param {string} gesture
  903.    * @return Boolean `gesture` is a valid gesture
  904.    */
  905.   scope.deactivateGesture = function(node, gesture) {
  906.     var g = gesture.toLowerCase();
  907.     var dep = dispatcher.dependencyMap[g];
  908.     if (dep) {
  909.       if (node._pgListeners > 0) {
  910.         node._pgListeners--;
  911.       }
  912.       if (node._pgListeners === 0) {
  913.         dispatcher.unregister(node);
  914.       }
  915.       if (node._pgEvents) {
  916.         if (node._pgEvents[g] > 0) {
  917.           node._pgEvents[g]--;
  918.         } else {
  919.           node._pgEvents[g] = 0;
  920.         }
  921.       }
  922.     }
  923.     return Boolean(dep);
  924.   };
  925.  
  926.   /**
  927.    * Stop listening for `gesture` from `node` with `handler` function.
  928.    *
  929.    * @param {Element} node
  930.    * @param {string} gesture
  931.    * @param {Function} handler
  932.    * @param {Boolean} capture
  933.    */
  934.   scope.removeEventListener = function(node, gesture, handler, capture) {
  935.     if (handler) {
  936.       scope.deactivateGesture(node, gesture);
  937.       node.removeEventListener(gesture, handler, capture);
  938.     }
  939.   };
  940. })(window.PolymerGestures);
  941.  
  942. (function(scope) {
  943.   var dispatcher = scope.dispatcher;
  944.   var pointermap = dispatcher.pointermap;
  945.   // radius around touchend that swallows mouse events
  946.   var DEDUP_DIST = 25;
  947.  
  948.   var WHICH_TO_BUTTONS = [0, 1, 4, 2];
  949.  
  950.   var CURRENT_BUTTONS = 0;
  951.  
  952.   var FIREFOX_LINUX = /Linux.*Firefox\//i;
  953.  
  954.   var HAS_BUTTONS = (function() {
  955.     // firefox on linux returns spec-incorrect values for mouseup.buttons
  956.     // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent.buttons#See_also
  957.     // https://codereview.chromium.org/727593003/#msg16
  958.     if (FIREFOX_LINUX.test(navigator.userAgent)) {
  959.       return false;
  960.     }
  961.     try {
  962.       return new MouseEvent('test', {buttons: 1}).buttons === 1;
  963.     } catch (e) {
  964.       return false;
  965.     }
  966.   })();
  967.  
  968.   // handler block for native mouse events
  969.   var mouseEvents = {
  970.     POINTER_ID: 1,
  971.     POINTER_TYPE: 'mouse',
  972.     events: [
  973.       'mousedown',
  974.       'mousemove',
  975.       'mouseup'
  976.     ],
  977.     exposes: [
  978.       'down',
  979.       'up',
  980.       'move'
  981.     ],
  982.     register: function(target) {
  983.       dispatcher.listen(target, this.events);
  984.     },
  985.     unregister: function(target) {
  986.       if (target === document) {
  987.         return;
  988.       }
  989.       dispatcher.unlisten(target, this.events);
  990.     },
  991.     lastTouches: [],
  992.     // collide with the global mouse listener
  993.     isEventSimulatedFromTouch: function(inEvent) {
  994.       var lts = this.lastTouches;
  995.       var x = inEvent.clientX, y = inEvent.clientY;
  996.       for (var i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) {
  997.         // simulated mouse events will be swallowed near a primary touchend
  998.         var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y);
  999.         if (dx <= DEDUP_DIST && dy <= DEDUP_DIST) {
  1000.           return true;
  1001.         }
  1002.       }
  1003.     },
  1004.     prepareEvent: function(inEvent) {
  1005.       var e = dispatcher.cloneEvent(inEvent);
  1006.       e.pointerId = this.POINTER_ID;
  1007.       e.isPrimary = true;
  1008.       e.pointerType = this.POINTER_TYPE;
  1009.       e._source = 'mouse';
  1010.       if (!HAS_BUTTONS) {
  1011.         var type = inEvent.type;
  1012.         var bit = WHICH_TO_BUTTONS[inEvent.which] || 0;
  1013.         if (type === 'mousedown') {
  1014.           CURRENT_BUTTONS |= bit;
  1015.         } else if (type === 'mouseup') {
  1016.           CURRENT_BUTTONS &= ~bit;
  1017.         }
  1018.         e.buttons = CURRENT_BUTTONS;
  1019.       }
  1020.       return e;
  1021.     },
  1022.     mousedown: function(inEvent) {
  1023.       if (!this.isEventSimulatedFromTouch(inEvent)) {
  1024.         var p = pointermap.has(this.POINTER_ID);
  1025.         var e = this.prepareEvent(inEvent);
  1026.         e.target = scope.findTarget(inEvent);
  1027.         pointermap.set(this.POINTER_ID, e.target);
  1028.         dispatcher.down(e);
  1029.       }
  1030.     },
  1031.     mousemove: function(inEvent) {
  1032.       if (!this.isEventSimulatedFromTouch(inEvent)) {
  1033.         var target = pointermap.get(this.POINTER_ID);
  1034.         if (target) {
  1035.           var e = this.prepareEvent(inEvent);
  1036.           e.target = target;
  1037.           // handle case where we missed a mouseup
  1038.           if ((HAS_BUTTONS ? e.buttons : e.which) === 0) {
  1039.             if (!HAS_BUTTONS) {
  1040.               CURRENT_BUTTONS = e.buttons = 0;
  1041.             }
  1042.             dispatcher.cancel(e);
  1043.             this.cleanupMouse(e.buttons);
  1044.           } else {
  1045.             dispatcher.move(e);
  1046.           }
  1047.         }
  1048.       }
  1049.     },
  1050.     mouseup: function(inEvent) {
  1051.       if (!this.isEventSimulatedFromTouch(inEvent)) {
  1052.         var e = this.prepareEvent(inEvent);
  1053.         e.relatedTarget = scope.findTarget(inEvent);
  1054.         e.target = pointermap.get(this.POINTER_ID);
  1055.         dispatcher.up(e);
  1056.         this.cleanupMouse(e.buttons);
  1057.       }
  1058.     },
  1059.     cleanupMouse: function(buttons) {
  1060.       if (buttons === 0) {
  1061.         pointermap.delete(this.POINTER_ID);
  1062.       }
  1063.     }
  1064.   };
  1065.  
  1066.   scope.mouseEvents = mouseEvents;
  1067. })(window.PolymerGestures);
  1068.  
  1069. (function(scope) {
  1070.   var dispatcher = scope.dispatcher;
  1071.   var allShadows = scope.targetFinding.allShadows.bind(scope.targetFinding);
  1072.   var pointermap = dispatcher.pointermap;
  1073.   var touchMap = Array.prototype.map.call.bind(Array.prototype.map);
  1074.   // This should be long enough to ignore compat mouse events made by touch
  1075.   var DEDUP_TIMEOUT = 2500;
  1076.   var DEDUP_DIST = 25;
  1077.   var CLICK_COUNT_TIMEOUT = 200;
  1078.   var HYSTERESIS = 20;
  1079.   var ATTRIB = 'touch-action';
  1080.   // TODO(dfreedm): disable until http://crbug.com/399765 is resolved
  1081.   // var HAS_TOUCH_ACTION = ATTRIB in document.head.style;
  1082.   var HAS_TOUCH_ACTION = false;
  1083.  
  1084.   // handler block for native touch events
  1085.   var touchEvents = {
  1086.     IS_IOS: false,
  1087.     events: [
  1088.       'touchstart',
  1089.       'touchmove',
  1090.       'touchend',
  1091.       'touchcancel'
  1092.     ],
  1093.     exposes: [
  1094.       'down',
  1095.       'up',
  1096.       'move'
  1097.     ],
  1098.     register: function(target, initial) {
  1099.       if (this.IS_IOS ? initial : !initial) {
  1100.         dispatcher.listen(target, this.events);
  1101.       }
  1102.     },
  1103.     unregister: function(target) {
  1104.       if (!this.IS_IOS) {
  1105.         dispatcher.unlisten(target, this.events);
  1106.       }
  1107.     },
  1108.     scrollTypes: {
  1109.       EMITTER: 'none',
  1110.       XSCROLLER: 'pan-x',
  1111.       YSCROLLER: 'pan-y',
  1112.     },
  1113.     touchActionToScrollType: function(touchAction) {
  1114.       var t = touchAction;
  1115.       var st = this.scrollTypes;
  1116.       if (t === st.EMITTER) {
  1117.         return 'none';
  1118.       } else if (t === st.XSCROLLER) {
  1119.         return 'X';
  1120.       } else if (t === st.YSCROLLER) {
  1121.         return 'Y';
  1122.       } else {
  1123.         return 'XY';
  1124.       }
  1125.     },
  1126.     POINTER_TYPE: 'touch',
  1127.     firstTouch: null,
  1128.     isPrimaryTouch: function(inTouch) {
  1129.       return this.firstTouch === inTouch.identifier;
  1130.     },
  1131.     setPrimaryTouch: function(inTouch) {
  1132.       // set primary touch if there no pointers, or the only pointer is the mouse
  1133.       if (pointermap.pointers() === 0 || (pointermap.pointers() === 1 && pointermap.has(1))) {
  1134.         this.firstTouch = inTouch.identifier;
  1135.         this.firstXY = {X: inTouch.clientX, Y: inTouch.clientY};
  1136.         this.firstTarget = inTouch.target;
  1137.         this.scrolling = null;
  1138.         this.cancelResetClickCount();
  1139.       }
  1140.     },
  1141.     removePrimaryPointer: function(inPointer) {
  1142.       if (inPointer.isPrimary) {
  1143.         this.firstTouch = null;
  1144.         this.firstXY = null;
  1145.         this.resetClickCount();
  1146.       }
  1147.     },
  1148.     clickCount: 0,
  1149.     resetId: null,
  1150.     resetClickCount: function() {
  1151.       var fn = function() {
  1152.         this.clickCount = 0;
  1153.         this.resetId = null;
  1154.       }.bind(this);
  1155.       this.resetId = setTimeout(fn, CLICK_COUNT_TIMEOUT);
  1156.     },
  1157.     cancelResetClickCount: function() {
  1158.       if (this.resetId) {
  1159.         clearTimeout(this.resetId);
  1160.       }
  1161.     },
  1162.     typeToButtons: function(type) {
  1163.       var ret = 0;
  1164.       if (type === 'touchstart' || type === 'touchmove') {
  1165.         ret = 1;
  1166.       }
  1167.       return ret;
  1168.     },
  1169.     findTarget: function(touch, id) {
  1170.       if (this.currentTouchEvent.type === 'touchstart') {
  1171.         if (this.isPrimaryTouch(touch)) {
  1172.           var fastPath = {
  1173.             clientX: touch.clientX,
  1174.             clientY: touch.clientY,
  1175.             path: this.currentTouchEvent.path,
  1176.             target: this.currentTouchEvent.target
  1177.           };
  1178.           return scope.findTarget(fastPath);
  1179.         } else {
  1180.           return scope.findTarget(touch);
  1181.         }
  1182.       }
  1183.       // reuse target we found in touchstart
  1184.       return pointermap.get(id);
  1185.     },
  1186.     touchToPointer: function(inTouch) {
  1187.       var cte = this.currentTouchEvent;
  1188.       var e = dispatcher.cloneEvent(inTouch);
  1189.       // Spec specifies that pointerId 1 is reserved for Mouse.
  1190.       // Touch identifiers can start at 0.
  1191.       // Add 2 to the touch identifier for compatibility.
  1192.       var id = e.pointerId = inTouch.identifier + 2;
  1193.       e.target = this.findTarget(inTouch, id);
  1194.       e.bubbles = true;
  1195.       e.cancelable = true;
  1196.       e.detail = this.clickCount;
  1197.       e.buttons = this.typeToButtons(cte.type);
  1198.       e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0;
  1199.       e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0;
  1200.       e.pressure = inTouch.webkitForce || inTouch.force || 0.5;
  1201.       e.isPrimary = this.isPrimaryTouch(inTouch);
  1202.       e.pointerType = this.POINTER_TYPE;
  1203.       e._source = 'touch';
  1204.       // forward touch preventDefaults
  1205.       var self = this;
  1206.       e.preventDefault = function() {
  1207.         self.scrolling = false;
  1208.         self.firstXY = null;
  1209.         cte.preventDefault();
  1210.       };
  1211.       return e;
  1212.     },
  1213.     processTouches: function(inEvent, inFunction) {
  1214.       var tl = inEvent.changedTouches;
  1215.       this.currentTouchEvent = inEvent;
  1216.       for (var i = 0, t, p; i < tl.length; i++) {
  1217.         t = tl[i];
  1218.         p = this.touchToPointer(t);
  1219.         if (inEvent.type === 'touchstart') {
  1220.           pointermap.set(p.pointerId, p.target);
  1221.         }
  1222.         if (pointermap.has(p.pointerId)) {
  1223.           inFunction.call(this, p);
  1224.         }
  1225.         if (inEvent.type === 'touchend' || inEvent._cancel) {
  1226.           this.cleanUpPointer(p);
  1227.         }
  1228.       }
  1229.     },
  1230.     // For single axis scrollers, determines whether the element should emit
  1231.     // pointer events or behave as a scroller
  1232.     shouldScroll: function(inEvent) {
  1233.       if (this.firstXY) {
  1234.         var ret;
  1235.         var touchAction = scope.targetFinding.findTouchAction(inEvent);
  1236.         var scrollAxis = this.touchActionToScrollType(touchAction);
  1237.         if (scrollAxis === 'none') {
  1238.           // this element is a touch-action: none, should never scroll
  1239.           ret = false;
  1240.         } else if (scrollAxis === 'XY') {
  1241.           // this element should always scroll
  1242.           ret = true;
  1243.         } else {
  1244.           var t = inEvent.changedTouches[0];
  1245.           // check the intended scroll axis, and other axis
  1246.           var a = scrollAxis;
  1247.           var oa = scrollAxis === 'Y' ? 'X' : 'Y';
  1248.           var da = Math.abs(t['client' + a] - this.firstXY[a]);
  1249.           var doa = Math.abs(t['client' + oa] - this.firstXY[oa]);
  1250.           // if delta in the scroll axis > delta other axis, scroll instead of
  1251.           // making events
  1252.           ret = da >= doa;
  1253.         }
  1254.         return ret;
  1255.       }
  1256.     },
  1257.     findTouch: function(inTL, inId) {
  1258.       for (var i = 0, l = inTL.length, t; i < l && (t = inTL[i]); i++) {
  1259.         if (t.identifier === inId) {
  1260.           return true;
  1261.         }
  1262.       }
  1263.     },
  1264.     // In some instances, a touchstart can happen without a touchend. This
  1265.     // leaves the pointermap in a broken state.
  1266.     // Therefore, on every touchstart, we remove the touches that did not fire a
  1267.     // touchend event.
  1268.     // To keep state globally consistent, we fire a
  1269.     // pointercancel for this "abandoned" touch
  1270.     vacuumTouches: function(inEvent) {
  1271.       var tl = inEvent.touches;
  1272.       // pointermap.pointers() should be < tl.length here, as the touchstart has not
  1273.       // been processed yet.
  1274.       if (pointermap.pointers() >= tl.length) {
  1275.         var d = [];
  1276.         pointermap.forEach(function(value, key) {
  1277.           // Never remove pointerId == 1, which is mouse.
  1278.           // Touch identifiers are 2 smaller than their pointerId, which is the
  1279.           // index in pointermap.
  1280.           if (key !== 1 && !this.findTouch(tl, key - 2)) {
  1281.             var p = value;
  1282.             d.push(p);
  1283.           }
  1284.         }, this);
  1285.         d.forEach(function(p) {
  1286.           this.cancel(p);
  1287.           pointermap.delete(p.pointerId);
  1288.         }, this);
  1289.       }
  1290.     },
  1291.     touchstart: function(inEvent) {
  1292.       this.vacuumTouches(inEvent);
  1293.       this.setPrimaryTouch(inEvent.changedTouches[0]);
  1294.       this.dedupSynthMouse(inEvent);
  1295.       if (!this.scrolling) {
  1296.         this.clickCount++;
  1297.         this.processTouches(inEvent, this.down);
  1298.       }
  1299.     },
  1300.     down: function(inPointer) {
  1301.       dispatcher.down(inPointer);
  1302.     },
  1303.     touchmove: function(inEvent) {
  1304.       if (HAS_TOUCH_ACTION) {
  1305.         // touchevent.cancelable == false is sent when the page is scrolling under native Touch Action in Chrome 36
  1306.         // https://groups.google.com/a/chromium.org/d/msg/input-dev/wHnyukcYBcA/b9kmtwM1jJQJ
  1307.         if (inEvent.cancelable) {
  1308.           this.processTouches(inEvent, this.move);
  1309.         }
  1310.       } else {
  1311.         if (!this.scrolling) {
  1312.           if (this.scrolling === null && this.shouldScroll(inEvent)) {
  1313.             this.scrolling = true;
  1314.           } else {
  1315.             this.scrolling = false;
  1316.             inEvent.preventDefault();
  1317.             this.processTouches(inEvent, this.move);
  1318.           }
  1319.         } else if (this.firstXY) {
  1320.           var t = inEvent.changedTouches[0];
  1321.           var dx = t.clientX - this.firstXY.X;
  1322.           var dy = t.clientY - this.firstXY.Y;
  1323.           var dd = Math.sqrt(dx * dx + dy * dy);
  1324.           if (dd >= HYSTERESIS) {
  1325.             this.touchcancel(inEvent);
  1326.             this.scrolling = true;
  1327.             this.firstXY = null;
  1328.           }
  1329.         }
  1330.       }
  1331.     },
  1332.     move: function(inPointer) {
  1333.       dispatcher.move(inPointer);
  1334.     },
  1335.     touchend: function(inEvent) {
  1336.       this.dedupSynthMouse(inEvent);
  1337.       this.processTouches(inEvent, this.up);
  1338.     },
  1339.     up: function(inPointer) {
  1340.       inPointer.relatedTarget = scope.findTarget(inPointer);
  1341.       dispatcher.up(inPointer);
  1342.     },
  1343.     cancel: function(inPointer) {
  1344.       dispatcher.cancel(inPointer);
  1345.     },
  1346.     touchcancel: function(inEvent) {
  1347.       inEvent._cancel = true;
  1348.       this.processTouches(inEvent, this.cancel);
  1349.     },
  1350.     cleanUpPointer: function(inPointer) {
  1351.       pointermap['delete'](inPointer.pointerId);
  1352.       this.removePrimaryPointer(inPointer);
  1353.     },
  1354.     // prevent synth mouse events from creating pointer events
  1355.     dedupSynthMouse: function(inEvent) {
  1356.       var lts = scope.mouseEvents.lastTouches;
  1357.       var t = inEvent.changedTouches[0];
  1358.       // only the primary finger will synth mouse events
  1359.       if (this.isPrimaryTouch(t)) {
  1360.         // remember x/y of last touch
  1361.         var lt = {x: t.clientX, y: t.clientY};
  1362.         lts.push(lt);
  1363.         var fn = (function(lts, lt){
  1364.           var i = lts.indexOf(lt);
  1365.           if (i > -1) {
  1366.             lts.splice(i, 1);
  1367.           }
  1368.         }).bind(null, lts, lt);
  1369.         setTimeout(fn, DEDUP_TIMEOUT);
  1370.       }
  1371.     }
  1372.   };
  1373.  
  1374.   // prevent "ghost clicks" that come from elements that were removed in a touch handler
  1375.   var STOP_PROP_FN = Event.prototype.stopImmediatePropagation || Event.prototype.stopPropagation;
  1376.   document.addEventListener('click', function(ev) {
  1377.     var x = ev.clientX, y = ev.clientY;
  1378.     // check if a click is within DEDUP_DIST px radius of the touchstart
  1379.     var closeTo = function(touch) {
  1380.       var dx = Math.abs(x - touch.x), dy = Math.abs(y - touch.y);
  1381.       return (dx <= DEDUP_DIST && dy <= DEDUP_DIST);
  1382.     };
  1383.     // if click coordinates are close to touch coordinates, assume the click came from a touch
  1384.     var wasTouched = scope.mouseEvents.lastTouches.some(closeTo);
  1385.     // if the click came from touch, and the touchstart target is not in the path of the click event,
  1386.     // then the touchstart target was probably removed, and the click should be "busted"
  1387.     var path = scope.targetFinding.path(ev);
  1388.     if (wasTouched) {
  1389.       for (var i = 0; i < path.length; i++) {
  1390.         if (path[i] === touchEvents.firstTarget) {
  1391.           return;
  1392.         }
  1393.       }
  1394.       ev.preventDefault();
  1395.       STOP_PROP_FN.call(ev);
  1396.     }
  1397.   }, true);
  1398.  
  1399.   scope.touchEvents = touchEvents;
  1400. })(window.PolymerGestures);
  1401.  
  1402. (function(scope) {
  1403.   var dispatcher = scope.dispatcher;
  1404.   var pointermap = dispatcher.pointermap;
  1405.   var HAS_BITMAP_TYPE = window.MSPointerEvent && typeof window.MSPointerEvent.MSPOINTER_TYPE_MOUSE === 'number';
  1406.   var msEvents = {
  1407.     events: [
  1408.       'MSPointerDown',
  1409.       'MSPointerMove',
  1410.       'MSPointerUp',
  1411.       'MSPointerCancel',
  1412.     ],
  1413.     register: function(target) {
  1414.       dispatcher.listen(target, this.events);
  1415.     },
  1416.     unregister: function(target) {
  1417.       if (target === document) {
  1418.         return;
  1419.       }
  1420.       dispatcher.unlisten(target, this.events);
  1421.     },
  1422.     POINTER_TYPES: [
  1423.       '',
  1424.       'unavailable',
  1425.       'touch',
  1426.       'pen',
  1427.       'mouse'
  1428.     ],
  1429.     prepareEvent: function(inEvent) {
  1430.       var e = inEvent;
  1431.       e = dispatcher.cloneEvent(inEvent);
  1432.       if (HAS_BITMAP_TYPE) {
  1433.         e.pointerType = this.POINTER_TYPES[inEvent.pointerType];
  1434.       }
  1435.       e._source = 'ms';
  1436.       return e;
  1437.     },
  1438.     cleanup: function(id) {
  1439.       pointermap['delete'](id);
  1440.     },
  1441.     MSPointerDown: function(inEvent) {
  1442.       var e = this.prepareEvent(inEvent);
  1443.       e.target = scope.findTarget(inEvent);
  1444.       pointermap.set(inEvent.pointerId, e.target);
  1445.       dispatcher.down(e);
  1446.     },
  1447.     MSPointerMove: function(inEvent) {
  1448.       var target = pointermap.get(inEvent.pointerId);
  1449.       if (target) {
  1450.         var e = this.prepareEvent(inEvent);
  1451.         e.target = target;
  1452.         dispatcher.move(e);
  1453.       }
  1454.     },
  1455.     MSPointerUp: function(inEvent) {
  1456.       var e = this.prepareEvent(inEvent);
  1457.       e.relatedTarget = scope.findTarget(inEvent);
  1458.       e.target = pointermap.get(e.pointerId);
  1459.       dispatcher.up(e);
  1460.       this.cleanup(inEvent.pointerId);
  1461.     },
  1462.     MSPointerCancel: function(inEvent) {
  1463.       var e = this.prepareEvent(inEvent);
  1464.       e.relatedTarget = scope.findTarget(inEvent);
  1465.       e.target = pointermap.get(e.pointerId);
  1466.       dispatcher.cancel(e);
  1467.       this.cleanup(inEvent.pointerId);
  1468.     }
  1469.   };
  1470.  
  1471.   scope.msEvents = msEvents;
  1472. })(window.PolymerGestures);
  1473.  
  1474. (function(scope) {
  1475.   var dispatcher = scope.dispatcher;
  1476.   var pointermap = dispatcher.pointermap;
  1477.   var pointerEvents = {
  1478.     events: [
  1479.       'pointerdown',
  1480.       'pointermove',
  1481.       'pointerup',
  1482.       'pointercancel'
  1483.     ],
  1484.     prepareEvent: function(inEvent) {
  1485.       var e = dispatcher.cloneEvent(inEvent);
  1486.       e._source = 'pointer';
  1487.       return e;
  1488.     },
  1489.     register: function(target) {
  1490.       dispatcher.listen(target, this.events);
  1491.     },
  1492.     unregister: function(target) {
  1493.       if (target === document) {
  1494.         return;
  1495.       }
  1496.       dispatcher.unlisten(target, this.events);
  1497.     },
  1498.     cleanup: function(id) {
  1499.       pointermap['delete'](id);
  1500.     },
  1501.     pointerdown: function(inEvent) {
  1502.       var e = this.prepareEvent(inEvent);
  1503.       e.target = scope.findTarget(inEvent);
  1504.       pointermap.set(e.pointerId, e.target);
  1505.       dispatcher.down(e);
  1506.     },
  1507.     pointermove: function(inEvent) {
  1508.       var target = pointermap.get(inEvent.pointerId);
  1509.       if (target) {
  1510.         var e = this.prepareEvent(inEvent);
  1511.         e.target = target;
  1512.         dispatcher.move(e);
  1513.       }
  1514.     },
  1515.     pointerup: function(inEvent) {
  1516.       var e = this.prepareEvent(inEvent);
  1517.       e.relatedTarget = scope.findTarget(inEvent);
  1518.       e.target = pointermap.get(e.pointerId);
  1519.       dispatcher.up(e);
  1520.       this.cleanup(inEvent.pointerId);
  1521.     },
  1522.     pointercancel: function(inEvent) {
  1523.       var e = this.prepareEvent(inEvent);
  1524.       e.relatedTarget = scope.findTarget(inEvent);
  1525.       e.target = pointermap.get(e.pointerId);
  1526.       dispatcher.cancel(e);
  1527.       this.cleanup(inEvent.pointerId);
  1528.     }
  1529.   };
  1530.  
  1531.   scope.pointerEvents = pointerEvents;
  1532. })(window.PolymerGestures);
  1533.  
  1534. /**
  1535.  * This module contains the handlers for native platform events.
  1536.  * From here, the dispatcher is called to create unified pointer events.
  1537.  * Included are touch events (v1), mouse events, and MSPointerEvents.
  1538.  */
  1539. (function(scope) {
  1540.  
  1541.   var dispatcher = scope.dispatcher;
  1542.   var nav = window.navigator;
  1543.  
  1544.   if (window.PointerEvent) {
  1545.     dispatcher.registerSource('pointer', scope.pointerEvents);
  1546.   } else if (nav.msPointerEnabled) {
  1547.     dispatcher.registerSource('ms', scope.msEvents);
  1548.   } else {
  1549.     dispatcher.registerSource('mouse', scope.mouseEvents);
  1550.     if (window.ontouchstart !== undefined) {
  1551.       dispatcher.registerSource('touch', scope.touchEvents);
  1552.     }
  1553.   }
  1554.  
  1555.   // Work around iOS bugs https://bugs.webkit.org/show_bug.cgi?id=135628 and https://bugs.webkit.org/show_bug.cgi?id=136506
  1556.   var ua = navigator.userAgent;
  1557.   var IS_IOS = ua.match(/iPad|iPhone|iPod/) && 'ontouchstart' in window;
  1558.  
  1559.   dispatcher.IS_IOS = IS_IOS;
  1560.   scope.touchEvents.IS_IOS = IS_IOS;
  1561.  
  1562.   dispatcher.register(document, true);
  1563. })(window.PolymerGestures);
  1564.  
  1565. /**
  1566.  * This event denotes the beginning of a series of tracking events.
  1567.  *
  1568.  * @module PointerGestures
  1569.  * @submodule Events
  1570.  * @class trackstart
  1571.  */
  1572. /**
  1573.  * Pixels moved in the x direction since trackstart.
  1574.  * @type Number
  1575.  * @property dx
  1576.  */
  1577. /**
  1578.  * Pixes moved in the y direction since trackstart.
  1579.  * @type Number
  1580.  * @property dy
  1581.  */
  1582. /**
  1583.  * Pixels moved in the x direction since the last track.
  1584.  * @type Number
  1585.  * @property ddx
  1586.  */
  1587. /**
  1588.  * Pixles moved in the y direction since the last track.
  1589.  * @type Number
  1590.  * @property ddy
  1591.  */
  1592. /**
  1593.  * The clientX position of the track gesture.
  1594.  * @type Number
  1595.  * @property clientX
  1596.  */
  1597. /**
  1598.  * The clientY position of the track gesture.
  1599.  * @type Number
  1600.  * @property clientY
  1601.  */
  1602. /**
  1603.  * The pageX position of the track gesture.
  1604.  * @type Number
  1605.  * @property pageX
  1606.  */
  1607. /**
  1608.  * The pageY position of the track gesture.
  1609.  * @type Number
  1610.  * @property pageY
  1611.  */
  1612. /**
  1613.  * The screenX position of the track gesture.
  1614.  * @type Number
  1615.  * @property screenX
  1616.  */
  1617. /**
  1618.  * The screenY position of the track gesture.
  1619.  * @type Number
  1620.  * @property screenY
  1621.  */
  1622. /**
  1623.  * The last x axis direction of the pointer.
  1624.  * @type Number
  1625.  * @property xDirection
  1626.  */
  1627. /**
  1628.  * The last y axis direction of the pointer.
  1629.  * @type Number
  1630.  * @property yDirection
  1631.  */
  1632. /**
  1633.  * A shared object between all tracking events.
  1634.  * @type Object
  1635.  * @property trackInfo
  1636.  */
  1637. /**
  1638.  * The element currently under the pointer.
  1639.  * @type Element
  1640.  * @property relatedTarget
  1641.  */
  1642. /**
  1643.  * The type of pointer that make the track gesture.
  1644.  * @type String
  1645.  * @property pointerType
  1646.  */
  1647. /**
  1648.  *
  1649.  * This event fires for all pointer movement being tracked.
  1650.  *
  1651.  * @class track
  1652.  * @extends trackstart
  1653.  */
  1654. /**
  1655.  * This event fires when the pointer is no longer being tracked.
  1656.  *
  1657.  * @class trackend
  1658.  * @extends trackstart
  1659.  */
  1660.  
  1661.  (function(scope) {
  1662.    var dispatcher = scope.dispatcher;
  1663.    var eventFactory = scope.eventFactory;
  1664.    var pointermap = new scope.PointerMap();
  1665.    var track = {
  1666.      events: [
  1667.        'down',
  1668.        'move',
  1669.        'up',
  1670.      ],
  1671.      exposes: [
  1672.       'trackstart',
  1673.       'track',
  1674.       'trackx',
  1675.       'tracky',
  1676.       'trackend'
  1677.      ],
  1678.      defaultActions: {
  1679.        'track': 'none',
  1680.        'trackx': 'pan-y',
  1681.        'tracky': 'pan-x'
  1682.      },
  1683.      WIGGLE_THRESHOLD: 4,
  1684.      clampDir: function(inDelta) {
  1685.        return inDelta > 0 ? 1 : -1;
  1686.      },
  1687.      calcPositionDelta: function(inA, inB) {
  1688.        var x = 0, y = 0;
  1689.        if (inA && inB) {
  1690.          x = inB.pageX - inA.pageX;
  1691.          y = inB.pageY - inA.pageY;
  1692.        }
  1693.        return {x: x, y: y};
  1694.      },
  1695.      fireTrack: function(inType, inEvent, inTrackingData) {
  1696.        var t = inTrackingData;
  1697.        var d = this.calcPositionDelta(t.downEvent, inEvent);
  1698.        var dd = this.calcPositionDelta(t.lastMoveEvent, inEvent);
  1699.        if (dd.x) {
  1700.          t.xDirection = this.clampDir(dd.x);
  1701.        } else if (inType === 'trackx') {
  1702.          return;
  1703.        }
  1704.        if (dd.y) {
  1705.          t.yDirection = this.clampDir(dd.y);
  1706.        } else if (inType === 'tracky') {
  1707.          return;
  1708.        }
  1709.        var gestureProto = {
  1710.          bubbles: true,
  1711.          cancelable: true,
  1712.          trackInfo: t.trackInfo,
  1713.          relatedTarget: inEvent.relatedTarget,
  1714.          pointerType: inEvent.pointerType,
  1715.          pointerId: inEvent.pointerId,
  1716.          _source: 'track'
  1717.        };
  1718.        if (inType !== 'tracky') {
  1719.          gestureProto.x = inEvent.x;
  1720.          gestureProto.dx = d.x;
  1721.          gestureProto.ddx = dd.x;
  1722.          gestureProto.clientX = inEvent.clientX;
  1723.          gestureProto.pageX = inEvent.pageX;
  1724.          gestureProto.screenX = inEvent.screenX;
  1725.          gestureProto.xDirection = t.xDirection;
  1726.        }
  1727.        if (inType !== 'trackx') {
  1728.          gestureProto.dy = d.y;
  1729.          gestureProto.ddy = dd.y;
  1730.          gestureProto.y = inEvent.y;
  1731.          gestureProto.clientY = inEvent.clientY;
  1732.          gestureProto.pageY = inEvent.pageY;
  1733.          gestureProto.screenY = inEvent.screenY;
  1734.          gestureProto.yDirection = t.yDirection;
  1735.        }
  1736.        var e = eventFactory.makeGestureEvent(inType, gestureProto);
  1737.        t.downTarget.dispatchEvent(e);
  1738.      },
  1739.      down: function(inEvent) {
  1740.        if (inEvent.isPrimary && (inEvent.pointerType === 'mouse' ? inEvent.buttons === 1 : true)) {
  1741.          var p = {
  1742.            downEvent: inEvent,
  1743.            downTarget: inEvent.target,
  1744.            trackInfo: {},
  1745.            lastMoveEvent: null,
  1746.            xDirection: 0,
  1747.            yDirection: 0,
  1748.            tracking: false
  1749.          };
  1750.          pointermap.set(inEvent.pointerId, p);
  1751.        }
  1752.      },
  1753.      move: function(inEvent) {
  1754.        var p = pointermap.get(inEvent.pointerId);
  1755.        if (p) {
  1756.          if (!p.tracking) {
  1757.            var d = this.calcPositionDelta(p.downEvent, inEvent);
  1758.            var move = d.x * d.x + d.y * d.y;
  1759.            // start tracking only if finger moves more than WIGGLE_THRESHOLD
  1760.            if (move > this.WIGGLE_THRESHOLD) {
  1761.              p.tracking = true;
  1762.              p.lastMoveEvent = p.downEvent;
  1763.              this.fireTrack('trackstart', inEvent, p);
  1764.            }
  1765.          }
  1766.          if (p.tracking) {
  1767.            this.fireTrack('track', inEvent, p);
  1768.            this.fireTrack('trackx', inEvent, p);
  1769.            this.fireTrack('tracky', inEvent, p);
  1770.          }
  1771.          p.lastMoveEvent = inEvent;
  1772.        }
  1773.      },
  1774.      up: function(inEvent) {
  1775.        var p = pointermap.get(inEvent.pointerId);
  1776.        if (p) {
  1777.          if (p.tracking) {
  1778.            this.fireTrack('trackend', inEvent, p);
  1779.          }
  1780.          pointermap.delete(inEvent.pointerId);
  1781.        }
  1782.      }
  1783.    };
  1784.    dispatcher.registerGesture('track', track);
  1785.  })(window.PolymerGestures);
  1786.  
  1787. /**
  1788.  * This event is fired when a pointer is held down for 200ms.
  1789.  *
  1790.  * @module PointerGestures
  1791.  * @submodule Events
  1792.  * @class hold
  1793.  */
  1794. /**
  1795.  * Type of pointer that made the holding event.
  1796.  * @type String
  1797.  * @property pointerType
  1798.  */
  1799. /**
  1800.  * Screen X axis position of the held pointer
  1801.  * @type Number
  1802.  * @property clientX
  1803.  */
  1804. /**
  1805.  * Screen Y axis position of the held pointer
  1806.  * @type Number
  1807.  * @property clientY
  1808.  */
  1809. /**
  1810.  * Type of pointer that made the holding event.
  1811.  * @type String
  1812.  * @property pointerType
  1813.  */
  1814. /**
  1815.  * This event is fired every 200ms while a pointer is held down.
  1816.  *
  1817.  * @class holdpulse
  1818.  * @extends hold
  1819.  */
  1820. /**
  1821.  * Milliseconds pointer has been held down.
  1822.  * @type Number
  1823.  * @property holdTime
  1824.  */
  1825. /**
  1826.  * This event is fired when a held pointer is released or moved.
  1827.  *
  1828.  * @class release
  1829.  */
  1830.  
  1831. (function(scope) {
  1832.   var dispatcher = scope.dispatcher;
  1833.   var eventFactory = scope.eventFactory;
  1834.   var hold = {
  1835.     // wait at least HOLD_DELAY ms between hold and pulse events
  1836.     HOLD_DELAY: 200,
  1837.     // pointer can move WIGGLE_THRESHOLD pixels before not counting as a hold
  1838.     WIGGLE_THRESHOLD: 16,
  1839.     events: [
  1840.       'down',
  1841.       'move',
  1842.       'up',
  1843.     ],
  1844.     exposes: [
  1845.       'hold',
  1846.       'holdpulse',
  1847.       'release'
  1848.     ],
  1849.     heldPointer: null,
  1850.     holdJob: null,
  1851.     pulse: function() {
  1852.       var hold = Date.now() - this.heldPointer.timeStamp;
  1853.       var type = this.held ? 'holdpulse' : 'hold';
  1854.       this.fireHold(type, hold);
  1855.       this.held = true;
  1856.     },
  1857.     cancel: function() {
  1858.       clearInterval(this.holdJob);
  1859.       if (this.held) {
  1860.         this.fireHold('release');
  1861.       }
  1862.       this.held = false;
  1863.       this.heldPointer = null;
  1864.       this.target = null;
  1865.       this.holdJob = null;
  1866.     },
  1867.     down: function(inEvent) {
  1868.       if (inEvent.isPrimary && !this.heldPointer) {
  1869.         this.heldPointer = inEvent;
  1870.         this.target = inEvent.target;
  1871.         this.holdJob = setInterval(this.pulse.bind(this), this.HOLD_DELAY);
  1872.       }
  1873.     },
  1874.     up: function(inEvent) {
  1875.       if (this.heldPointer && this.heldPointer.pointerId === inEvent.pointerId) {
  1876.         this.cancel();
  1877.       }
  1878.     },
  1879.     move: function(inEvent) {
  1880.       if (this.heldPointer && this.heldPointer.pointerId === inEvent.pointerId) {
  1881.         var x = inEvent.clientX - this.heldPointer.clientX;
  1882.         var y = inEvent.clientY - this.heldPointer.clientY;
  1883.         if ((x * x + y * y) > this.WIGGLE_THRESHOLD) {
  1884.           this.cancel();
  1885.         }
  1886.       }
  1887.     },
  1888.     fireHold: function(inType, inHoldTime) {
  1889.       var p = {
  1890.         bubbles: true,
  1891.         cancelable: true,
  1892.         pointerType: this.heldPointer.pointerType,
  1893.         pointerId: this.heldPointer.pointerId,
  1894.         x: this.heldPointer.clientX,
  1895.         y: this.heldPointer.clientY,
  1896.         _source: 'hold'
  1897.       };
  1898.       if (inHoldTime) {
  1899.         p.holdTime = inHoldTime;
  1900.       }
  1901.       var e = eventFactory.makeGestureEvent(inType, p);
  1902.       this.target.dispatchEvent(e);
  1903.     }
  1904.   };
  1905.   dispatcher.registerGesture('hold', hold);
  1906. })(window.PolymerGestures);
  1907.  
  1908. /**
  1909.  * This event is fired when a pointer quickly goes down and up, and is used to
  1910.  * denote activation.
  1911.  *
  1912.  * Any gesture event can prevent the tap event from being created by calling
  1913.  * `event.preventTap`.
  1914.  *
  1915.  * Any pointer event can prevent the tap by setting the `tapPrevented` property
  1916.  * on itself.
  1917.  *
  1918.  * @module PointerGestures
  1919.  * @submodule Events
  1920.  * @class tap
  1921.  */
  1922. /**
  1923.  * X axis position of the tap.
  1924.  * @property x
  1925.  * @type Number
  1926.  */
  1927. /**
  1928.  * Y axis position of the tap.
  1929.  * @property y
  1930.  * @type Number
  1931.  */
  1932. /**
  1933.  * Type of the pointer that made the tap.
  1934.  * @property pointerType
  1935.  * @type String
  1936.  */
  1937. (function(scope) {
  1938.   var dispatcher = scope.dispatcher;
  1939.   var eventFactory = scope.eventFactory;
  1940.   var pointermap = new scope.PointerMap();
  1941.   var tap = {
  1942.     events: [
  1943.       'down',
  1944.       'up'
  1945.     ],
  1946.     exposes: [
  1947.       'tap'
  1948.     ],
  1949.     down: function(inEvent) {
  1950.       if (inEvent.isPrimary && !inEvent.tapPrevented) {
  1951.         pointermap.set(inEvent.pointerId, {
  1952.           target: inEvent.target,
  1953.           buttons: inEvent.buttons,
  1954.           x: inEvent.clientX,
  1955.           y: inEvent.clientY
  1956.         });
  1957.       }
  1958.     },
  1959.     shouldTap: function(e, downState) {
  1960.       var tap = true;
  1961.       if (e.pointerType === 'mouse') {
  1962.         // only allow left click to tap for mouse
  1963.         tap = (e.buttons ^ 1) && (downState.buttons & 1);
  1964.       }
  1965.       return tap && !e.tapPrevented;
  1966.     },
  1967.     up: function(inEvent) {
  1968.       var start = pointermap.get(inEvent.pointerId);
  1969.       if (start && this.shouldTap(inEvent, start)) {
  1970.         // up.relatedTarget is target currently under finger
  1971.         var t = scope.targetFinding.LCA(start.target, inEvent.relatedTarget);
  1972.         if (t) {
  1973.           var e = eventFactory.makeGestureEvent('tap', {
  1974.             bubbles: true,
  1975.             cancelable: true,
  1976.             x: inEvent.clientX,
  1977.             y: inEvent.clientY,
  1978.             detail: inEvent.detail,
  1979.             pointerType: inEvent.pointerType,
  1980.             pointerId: inEvent.pointerId,
  1981.             altKey: inEvent.altKey,
  1982.             ctrlKey: inEvent.ctrlKey,
  1983.             metaKey: inEvent.metaKey,
  1984.             shiftKey: inEvent.shiftKey,
  1985.             _source: 'tap'
  1986.           });
  1987.           t.dispatchEvent(e);
  1988.         }
  1989.       }
  1990.       pointermap.delete(inEvent.pointerId);
  1991.     }
  1992.   };
  1993.   // patch eventFactory to remove id from tap's pointermap for preventTap calls
  1994.   eventFactory.preventTap = function(e) {
  1995.     return function() {
  1996.       e.tapPrevented = true;
  1997.       pointermap.delete(e.pointerId);
  1998.     };
  1999.   };
  2000.   dispatcher.registerGesture('tap', tap);
  2001. })(window.PolymerGestures);
  2002.  
  2003. /*
  2004.  * Basic strategy: find the farthest apart points, use as diameter of circle
  2005.  * react to size change and rotation of the chord
  2006.  */
  2007.  
  2008. /**
  2009.  * @module pointer-gestures
  2010.  * @submodule Events
  2011.  * @class pinch
  2012.  */
  2013. /**
  2014.  * Scale of the pinch zoom gesture
  2015.  * @property scale
  2016.  * @type Number
  2017.  */
  2018. /**
  2019.  * Center X position of pointers causing pinch
  2020.  * @property centerX
  2021.  * @type Number
  2022.  */
  2023. /**
  2024.  * Center Y position of pointers causing pinch
  2025.  * @property centerY
  2026.  * @type Number
  2027.  */
  2028.  
  2029. /**
  2030.  * @module pointer-gestures
  2031.  * @submodule Events
  2032.  * @class rotate
  2033.  */
  2034. /**
  2035.  * Angle (in degrees) of rotation. Measured from starting positions of pointers.
  2036.  * @property angle
  2037.  * @type Number
  2038.  */
  2039. /**
  2040.  * Center X position of pointers causing rotation
  2041.  * @property centerX
  2042.  * @type Number
  2043.  */
  2044. /**
  2045.  * Center Y position of pointers causing rotation
  2046.  * @property centerY
  2047.  * @type Number
  2048.  */
  2049. (function(scope) {
  2050.   var dispatcher = scope.dispatcher;
  2051.   var eventFactory = scope.eventFactory;
  2052.   var pointermap = new scope.PointerMap();
  2053.   var RAD_TO_DEG = 180 / Math.PI;
  2054.   var pinch = {
  2055.     events: [
  2056.       'down',
  2057.       'up',
  2058.       'move',
  2059.       'cancel'
  2060.     ],
  2061.     exposes: [
  2062.       'pinchstart',
  2063.       'pinch',
  2064.       'pinchend',
  2065.       'rotate'
  2066.     ],
  2067.     defaultActions: {
  2068.       'pinch': 'none',
  2069.       'rotate': 'none'
  2070.     },
  2071.     reference: {},
  2072.     down: function(inEvent) {
  2073.       pointermap.set(inEvent.pointerId, inEvent);
  2074.       if (pointermap.pointers() == 2) {
  2075.         var points = this.calcChord();
  2076.         var angle = this.calcAngle(points);
  2077.         this.reference = {
  2078.           angle: angle,
  2079.           diameter: points.diameter,
  2080.           target: scope.targetFinding.LCA(points.a.target, points.b.target)
  2081.         };
  2082.  
  2083.         this.firePinch('pinchstart', points.diameter, points);
  2084.       }
  2085.     },
  2086.     up: function(inEvent) {
  2087.       var p = pointermap.get(inEvent.pointerId);
  2088.       var num = pointermap.pointers();
  2089.       if (p) {
  2090.         if (num === 2) {
  2091.           // fire 'pinchend' before deleting pointer
  2092.           var points = this.calcChord();
  2093.           this.firePinch('pinchend', points.diameter, points);
  2094.         }
  2095.         pointermap.delete(inEvent.pointerId);
  2096.       }
  2097.     },
  2098.     move: function(inEvent) {
  2099.       if (pointermap.has(inEvent.pointerId)) {
  2100.         pointermap.set(inEvent.pointerId, inEvent);
  2101.         if (pointermap.pointers() > 1) {
  2102.           this.calcPinchRotate();
  2103.         }
  2104.       }
  2105.     },
  2106.     cancel: function(inEvent) {
  2107.         this.up(inEvent);
  2108.     },
  2109.     firePinch: function(type, diameter, points) {
  2110.       var zoom = diameter / this.reference.diameter;
  2111.       var e = eventFactory.makeGestureEvent(type, {
  2112.         bubbles: true,
  2113.         cancelable: true,
  2114.         scale: zoom,
  2115.         centerX: points.center.x,
  2116.         centerY: points.center.y,
  2117.         _source: 'pinch'
  2118.       });
  2119.       this.reference.target.dispatchEvent(e);
  2120.     },
  2121.     fireRotate: function(angle, points) {
  2122.       var diff = Math.round((angle - this.reference.angle) % 360);
  2123.       var e = eventFactory.makeGestureEvent('rotate', {
  2124.         bubbles: true,
  2125.         cancelable: true,
  2126.         angle: diff,
  2127.         centerX: points.center.x,
  2128.         centerY: points.center.y,
  2129.         _source: 'pinch'
  2130.       });
  2131.       this.reference.target.dispatchEvent(e);
  2132.     },
  2133.     calcPinchRotate: function() {
  2134.       var points = this.calcChord();
  2135.       var diameter = points.diameter;
  2136.       var angle = this.calcAngle(points);
  2137.       if (diameter != this.reference.diameter) {
  2138.         this.firePinch('pinch', diameter, points);
  2139.       }
  2140.       if (angle != this.reference.angle) {
  2141.         this.fireRotate(angle, points);
  2142.       }
  2143.     },
  2144.     calcChord: function() {
  2145.       var pointers = [];
  2146.       pointermap.forEach(function(p) {
  2147.         pointers.push(p);
  2148.       });
  2149.       var dist = 0;
  2150.       // start with at least two pointers
  2151.       var points = {a: pointers[0], b: pointers[1]};
  2152.       var x, y, d;
  2153.       for (var i = 0; i < pointers.length; i++) {
  2154.         var a = pointers[i];
  2155.         for (var j = i + 1; j < pointers.length; j++) {
  2156.           var b = pointers[j];
  2157.           x = Math.abs(a.clientX - b.clientX);
  2158.           y = Math.abs(a.clientY - b.clientY);
  2159.           d = x + y;
  2160.           if (d > dist) {
  2161.             dist = d;
  2162.             points = {a: a, b: b};
  2163.           }
  2164.         }
  2165.       }
  2166.       x = Math.abs(points.a.clientX + points.b.clientX) / 2;
  2167.       y = Math.abs(points.a.clientY + points.b.clientY) / 2;
  2168.       points.center = { x: x, y: y };
  2169.       points.diameter = dist;
  2170.       return points;
  2171.     },
  2172.     calcAngle: function(points) {
  2173.       var x = points.a.clientX - points.b.clientX;
  2174.       var y = points.a.clientY - points.b.clientY;
  2175.       return (360 + Math.atan2(y, x) * RAD_TO_DEG) % 360;
  2176.     }
  2177.   };
  2178.   dispatcher.registerGesture('pinch', pinch);
  2179. })(window.PolymerGestures);
  2180.  
  2181. (function (global) {
  2182.     'use strict';
  2183.  
  2184.     var Token,
  2185.         TokenName,
  2186.         Syntax,
  2187.         Messages,
  2188.         source,
  2189.         index,
  2190.         length,
  2191.         delegate,
  2192.         lookahead,
  2193.         state;
  2194.  
  2195.     Token = {
  2196.         BooleanLiteral: 1,
  2197.         EOF: 2,
  2198.         Identifier: 3,
  2199.         Keyword: 4,
  2200.         NullLiteral: 5,
  2201.         NumericLiteral: 6,
  2202.         Punctuator: 7,
  2203.         StringLiteral: 8
  2204.     };
  2205.  
  2206.     TokenName = {};
  2207.     TokenName[Token.BooleanLiteral] = 'Boolean';
  2208.     TokenName[Token.EOF] = '<end>';
  2209.     TokenName[Token.Identifier] = 'Identifier';
  2210.     TokenName[Token.Keyword] = 'Keyword';
  2211.     TokenName[Token.NullLiteral] = 'Null';
  2212.     TokenName[Token.NumericLiteral] = 'Numeric';
  2213.     TokenName[Token.Punctuator] = 'Punctuator';
  2214.     TokenName[Token.StringLiteral] = 'String';
  2215.  
  2216.     Syntax = {
  2217.         ArrayExpression: 'ArrayExpression',
  2218.         BinaryExpression: 'BinaryExpression',
  2219.         CallExpression: 'CallExpression',
  2220.         ConditionalExpression: 'ConditionalExpression',
  2221.         EmptyStatement: 'EmptyStatement',
  2222.         ExpressionStatement: 'ExpressionStatement',
  2223.         Identifier: 'Identifier',
  2224.         Literal: 'Literal',
  2225.         LabeledStatement: 'LabeledStatement',
  2226.         LogicalExpression: 'LogicalExpression',
  2227.         MemberExpression: 'MemberExpression',
  2228.         ObjectExpression: 'ObjectExpression',
  2229.         Program: 'Program',
  2230.         Property: 'Property',
  2231.         ThisExpression: 'ThisExpression',
  2232.         UnaryExpression: 'UnaryExpression'
  2233.     };
  2234.  
  2235.     // Error messages should be identical to V8.
  2236.     Messages = {
  2237.         UnexpectedToken:  'Unexpected token %0',
  2238.         UnknownLabel: 'Undefined label \'%0\'',
  2239.         Redeclaration: '%0 \'%1\' has already been declared'
  2240.     };
  2241.  
  2242.     // Ensure the condition is true, otherwise throw an error.
  2243.     // This is only to have a better contract semantic, i.e. another safety net
  2244.     // to catch a logic error. The condition shall be fulfilled in normal case.
  2245.     // Do NOT use this to enforce a certain condition on any user input.
  2246.  
  2247.     function assert(condition, message) {
  2248.         if (!condition) {
  2249.             throw new Error('ASSERT: ' + message);
  2250.         }
  2251.     }
  2252.  
  2253.     function isDecimalDigit(ch) {
  2254.         return (ch >= 48 && ch <= 57);   // 0..9
  2255.     }
  2256.  
  2257.  
  2258.     // 7.2 White Space
  2259.  
  2260.     function isWhiteSpace(ch) {
  2261.         return (ch === 32) ||  // space
  2262.             (ch === 9) ||      // tab
  2263.             (ch === 0xB) ||
  2264.             (ch === 0xC) ||
  2265.             (ch === 0xA0) ||
  2266.             (ch >= 0x1680 && '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(String.fromCharCode(ch)) > 0);
  2267.     }
  2268.  
  2269.     // 7.3 Line Terminators
  2270.  
  2271.     function isLineTerminator(ch) {
  2272.         return (ch === 10) || (ch === 13) || (ch === 0x2028) || (ch === 0x2029);
  2273.     }
  2274.  
  2275.     // 7.6 Identifier Names and Identifiers
  2276.  
  2277.     function isIdentifierStart(ch) {
  2278.         return (ch === 36) || (ch === 95) ||  // $ (dollar) and _ (underscore)
  2279.             (ch >= 65 && ch <= 90) ||         // A..Z
  2280.             (ch >= 97 && ch <= 122);          // a..z
  2281.     }
  2282.  
  2283.     function isIdentifierPart(ch) {
  2284.         return (ch === 36) || (ch === 95) ||  // $ (dollar) and _ (underscore)
  2285.             (ch >= 65 && ch <= 90) ||         // A..Z
  2286.             (ch >= 97 && ch <= 122) ||        // a..z
  2287.             (ch >= 48 && ch <= 57);           // 0..9
  2288.     }
  2289.  
  2290.     // 7.6.1.1 Keywords
  2291.  
  2292.     function isKeyword(id) {
  2293.         return (id === 'this')
  2294.     }
  2295.  
  2296.     // 7.4 Comments
  2297.  
  2298.     function skipWhitespace() {
  2299.         while (index < length && isWhiteSpace(source.charCodeAt(index))) {
  2300.            ++index;
  2301.         }
  2302.     }
  2303.  
  2304.     function getIdentifier() {
  2305.         var start, ch;
  2306.  
  2307.         start = index++;
  2308.         while (index < length) {
  2309.             ch = source.charCodeAt(index);
  2310.             if (isIdentifierPart(ch)) {
  2311.                 ++index;
  2312.             } else {
  2313.                 break;
  2314.             }
  2315.         }
  2316.  
  2317.         return source.slice(start, index);
  2318.     }
  2319.  
  2320.     function scanIdentifier() {
  2321.         var start, id, type;
  2322.  
  2323.         start = index;
  2324.  
  2325.         id = getIdentifier();
  2326.  
  2327.         // There is no keyword or literal with only one character.
  2328.         // Thus, it must be an identifier.
  2329.         if (id.length === 1) {
  2330.             type = Token.Identifier;
  2331.         } else if (isKeyword(id)) {
  2332.             type = Token.Keyword;
  2333.         } else if (id === 'null') {
  2334.             type = Token.NullLiteral;
  2335.         } else if (id === 'true' || id === 'false') {
  2336.             type = Token.BooleanLiteral;
  2337.         } else {
  2338.             type = Token.Identifier;
  2339.         }
  2340.  
  2341.         return {
  2342.             type: type,
  2343.             value: id,
  2344.             range: [start, index]
  2345.         };
  2346.     }
  2347.  
  2348.  
  2349.     // 7.7 Punctuators
  2350.  
  2351.     function scanPunctuator() {
  2352.         var start = index,
  2353.             code = source.charCodeAt(index),
  2354.             code2,
  2355.             ch1 = source[index],
  2356.             ch2;
  2357.  
  2358.         switch (code) {
  2359.  
  2360.         // Check for most common single-character punctuators.
  2361.         case 46:   // . dot
  2362.         case 40:   // ( open bracket
  2363.         case 41:   // ) close bracket
  2364.         case 59:   // ; semicolon
  2365.         case 44:   // , comma
  2366.         case 123:  // { open curly brace
  2367.         case 125:  // } close curly brace
  2368.         case 91:   // [
  2369.         case 93:   // ]
  2370.         case 58:   // :
  2371.         case 63:   // ?
  2372.             ++index;
  2373.             return {
  2374.                 type: Token.Punctuator,
  2375.                 value: String.fromCharCode(code),
  2376.                 range: [start, index]
  2377.             };
  2378.  
  2379.         default:
  2380.             code2 = source.charCodeAt(index + 1);
  2381.  
  2382.             // '=' (char #61) marks an assignment or comparison operator.
  2383.             if (code2 === 61) {
  2384.                 switch (code) {
  2385.                 case 37:  // %
  2386.                 case 38:  // &
  2387.                 case 42:  // *:
  2388.                 case 43:  // +
  2389.                 case 45:  // -
  2390.                 case 47:  // /
  2391.                 case 60:  // <
  2392.                 case 62:  // >
  2393.                 case 124: // |
  2394.                     index += 2;
  2395.                     return {
  2396.                         type: Token.Punctuator,
  2397.                         value: String.fromCharCode(code) + String.fromCharCode(code2),
  2398.                         range: [start, index]
  2399.                     };
  2400.  
  2401.                 case 33: // !
  2402.                 case 61: // =
  2403.                     index += 2;
  2404.  
  2405.                     // !== and ===
  2406.                     if (source.charCodeAt(index) === 61) {
  2407.                         ++index;
  2408.                     }
  2409.                     return {
  2410.                         type: Token.Punctuator,
  2411.                         value: source.slice(start, index),
  2412.                         range: [start, index]
  2413.                     };
  2414.                 default:
  2415.                     break;
  2416.                 }
  2417.             }
  2418.             break;
  2419.         }
  2420.  
  2421.         // Peek more characters.
  2422.  
  2423.         ch2 = source[index + 1];
  2424.  
  2425.         // Other 2-character punctuators: && ||
  2426.  
  2427.         if (ch1 === ch2 && ('&|'.indexOf(ch1) >= 0)) {
  2428.             index += 2;
  2429.             return {
  2430.                 type: Token.Punctuator,
  2431.                 value: ch1 + ch2,
  2432.                 range: [start, index]
  2433.             };
  2434.         }
  2435.  
  2436.         if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
  2437.             ++index;
  2438.             return {
  2439.                 type: Token.Punctuator,
  2440.                 value: ch1,
  2441.                 range: [start, index]
  2442.             };
  2443.         }
  2444.  
  2445.         throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  2446.     }
  2447.  
  2448.     // 7.8.3 Numeric Literals
  2449.     function scanNumericLiteral() {
  2450.         var number, start, ch;
  2451.  
  2452.         ch = source[index];
  2453.         assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
  2454.             'Numeric literal must start with a decimal digit or a decimal point');
  2455.  
  2456.         start = index;
  2457.         number = '';
  2458.         if (ch !== '.') {
  2459.             number = source[index++];
  2460.             ch = source[index];
  2461.  
  2462.             // Hex number starts with '0x'.
  2463.             // Octal number starts with '0'.
  2464.             if (number === '0') {
  2465.                 // decimal number starts with '0' such as '09' is illegal.
  2466.                 if (ch && isDecimalDigit(ch.charCodeAt(0))) {
  2467.                     throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  2468.                 }
  2469.             }
  2470.  
  2471.             while (isDecimalDigit(source.charCodeAt(index))) {
  2472.                 number += source[index++];
  2473.             }
  2474.             ch = source[index];
  2475.         }
  2476.  
  2477.         if (ch === '.') {
  2478.             number += source[index++];
  2479.             while (isDecimalDigit(source.charCodeAt(index))) {
  2480.                 number += source[index++];
  2481.             }
  2482.             ch = source[index];
  2483.         }
  2484.  
  2485.         if (ch === 'e' || ch === 'E') {
  2486.             number += source[index++];
  2487.  
  2488.             ch = source[index];
  2489.             if (ch === '+' || ch === '-') {
  2490.                 number += source[index++];
  2491.             }
  2492.             if (isDecimalDigit(source.charCodeAt(index))) {
  2493.                 while (isDecimalDigit(source.charCodeAt(index))) {
  2494.                     number += source[index++];
  2495.                 }
  2496.             } else {
  2497.                 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  2498.             }
  2499.         }
  2500.  
  2501.         if (isIdentifierStart(source.charCodeAt(index))) {
  2502.             throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  2503.         }
  2504.  
  2505.         return {
  2506.             type: Token.NumericLiteral,
  2507.             value: parseFloat(number),
  2508.             range: [start, index]
  2509.         };
  2510.     }
  2511.  
  2512.     // 7.8.4 String Literals
  2513.  
  2514.     function scanStringLiteral() {
  2515.         var str = '', quote, start, ch, octal = false;
  2516.  
  2517.         quote = source[index];
  2518.         assert((quote === '\'' || quote === '"'),
  2519.             'String literal must starts with a quote');
  2520.  
  2521.         start = index;
  2522.         ++index;
  2523.  
  2524.         while (index < length) {
  2525.             ch = source[index++];
  2526.  
  2527.             if (ch === quote) {
  2528.                 quote = '';
  2529.                 break;
  2530.             } else if (ch === '\\') {
  2531.                 ch = source[index++];
  2532.                 if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
  2533.                     switch (ch) {
  2534.                     case 'n':
  2535.                         str += '\n';
  2536.                         break;
  2537.                     case 'r':
  2538.                         str += '\r';
  2539.                         break;
  2540.                     case 't':
  2541.                         str += '\t';
  2542.                         break;
  2543.                     case 'b':
  2544.                         str += '\b';
  2545.                         break;
  2546.                     case 'f':
  2547.                         str += '\f';
  2548.                         break;
  2549.                     case 'v':
  2550.                         str += '\x0B';
  2551.                         break;
  2552.  
  2553.                     default:
  2554.                         str += ch;
  2555.                         break;
  2556.                     }
  2557.                 } else {
  2558.                     if (ch ===  '\r' && source[index] === '\n') {
  2559.                         ++index;
  2560.                     }
  2561.                 }
  2562.             } else if (isLineTerminator(ch.charCodeAt(0))) {
  2563.                 break;
  2564.             } else {
  2565.                 str += ch;
  2566.             }
  2567.         }
  2568.  
  2569.         if (quote !== '') {
  2570.             throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
  2571.         }
  2572.  
  2573.         return {
  2574.             type: Token.StringLiteral,
  2575.             value: str,
  2576.             octal: octal,
  2577.             range: [start, index]
  2578.         };
  2579.     }
  2580.  
  2581.     function isIdentifierName(token) {
  2582.         return token.type === Token.Identifier ||
  2583.             token.type === Token.Keyword ||
  2584.             token.type === Token.BooleanLiteral ||
  2585.             token.type === Token.NullLiteral;
  2586.     }
  2587.  
  2588.     function advance() {
  2589.         var ch;
  2590.  
  2591.         skipWhitespace();
  2592.  
  2593.         if (index >= length) {
  2594.             return {
  2595.                 type: Token.EOF,
  2596.                 range: [index, index]
  2597.             };
  2598.         }
  2599.  
  2600.         ch = source.charCodeAt(index);
  2601.  
  2602.         // Very common: ( and ) and ;
  2603.         if (ch === 40 || ch === 41 || ch === 58) {
  2604.             return scanPunctuator();
  2605.         }
  2606.  
  2607.         // String literal starts with single quote (#39) or double quote (#34).
  2608.         if (ch === 39 || ch === 34) {
  2609.             return scanStringLiteral();
  2610.         }
  2611.  
  2612.         if (isIdentifierStart(ch)) {
  2613.             return scanIdentifier();
  2614.         }
  2615.  
  2616.         // Dot (.) char #46 can also start a floating-point number, hence the need
  2617.         // to check the next character.
  2618.         if (ch === 46) {
  2619.             if (isDecimalDigit(source.charCodeAt(index + 1))) {
  2620.                 return scanNumericLiteral();
  2621.             }
  2622.             return scanPunctuator();
  2623.         }
  2624.  
  2625.         if (isDecimalDigit(ch)) {
  2626.             return scanNumericLiteral();
  2627.         }
  2628.  
  2629.         return scanPunctuator();
  2630.     }
  2631.  
  2632.     function lex() {
  2633.         var token;
  2634.  
  2635.         token = lookahead;
  2636.         index = token.range[1];
  2637.  
  2638.         lookahead = advance();
  2639.  
  2640.         index = token.range[1];
  2641.  
  2642.         return token;
  2643.     }
  2644.  
  2645.     function peek() {
  2646.         var pos;
  2647.  
  2648.         pos = index;
  2649.         lookahead = advance();
  2650.         index = pos;
  2651.     }
  2652.  
  2653.     // Throw an exception
  2654.  
  2655.     function throwError(token, messageFormat) {
  2656.         var error,
  2657.             args = Array.prototype.slice.call(arguments, 2),
  2658.             msg = messageFormat.replace(
  2659.                 /%(\d)/g,
  2660.                 function (whole, index) {
  2661.                     assert(index < args.length, 'Message reference must be in range');
  2662.                     return args[index];
  2663.                 }
  2664.             );
  2665.  
  2666.         error = new Error(msg);
  2667.         error.index = index;
  2668.         error.description = msg;
  2669.         throw error;
  2670.     }
  2671.  
  2672.     // Throw an exception because of the token.
  2673.  
  2674.     function throwUnexpected(token) {
  2675.         throwError(token, Messages.UnexpectedToken, token.value);
  2676.     }
  2677.  
  2678.     // Expect the next token to match the specified punctuator.
  2679.     // If not, an exception will be thrown.
  2680.  
  2681.     function expect(value) {
  2682.         var token = lex();
  2683.         if (token.type !== Token.Punctuator || token.value !== value) {
  2684.             throwUnexpected(token);
  2685.         }
  2686.     }
  2687.  
  2688.     // Return true if the next token matches the specified punctuator.
  2689.  
  2690.     function match(value) {
  2691.         return lookahead.type === Token.Punctuator && lookahead.value === value;
  2692.     }
  2693.  
  2694.     // Return true if the next token matches the specified keyword
  2695.  
  2696.     function matchKeyword(keyword) {
  2697.         return lookahead.type === Token.Keyword && lookahead.value === keyword;
  2698.     }
  2699.  
  2700.     function consumeSemicolon() {
  2701.         // Catch the very common case first: immediately a semicolon (char #59).
  2702.         if (source.charCodeAt(index) === 59) {
  2703.             lex();
  2704.             return;
  2705.         }
  2706.  
  2707.         skipWhitespace();
  2708.  
  2709.         if (match(';')) {
  2710.             lex();
  2711.             return;
  2712.         }
  2713.  
  2714.         if (lookahead.type !== Token.EOF && !match('}')) {
  2715.             throwUnexpected(lookahead);
  2716.         }
  2717.     }
  2718.  
  2719.     // 11.1.4 Array Initialiser
  2720.  
  2721.     function parseArrayInitialiser() {
  2722.         var elements = [];
  2723.  
  2724.         expect('[');
  2725.  
  2726.         while (!match(']')) {
  2727.             if (match(',')) {
  2728.                 lex();
  2729.                 elements.push(null);
  2730.             } else {
  2731.                 elements.push(parseExpression());
  2732.  
  2733.                 if (!match(']')) {
  2734.                     expect(',');
  2735.                 }
  2736.             }
  2737.         }
  2738.  
  2739.         expect(']');
  2740.  
  2741.         return delegate.createArrayExpression(elements);
  2742.     }
  2743.  
  2744.     // 11.1.5 Object Initialiser
  2745.  
  2746.     function parseObjectPropertyKey() {
  2747.         var token;
  2748.  
  2749.         skipWhitespace();
  2750.         token = lex();
  2751.  
  2752.         // Note: This function is called only from parseObjectProperty(), where
  2753.         // EOF and Punctuator tokens are already filtered out.
  2754.         if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
  2755.             return delegate.createLiteral(token);
  2756.         }
  2757.  
  2758.         return delegate.createIdentifier(token.value);
  2759.     }
  2760.  
  2761.     function parseObjectProperty() {
  2762.         var token, key;
  2763.  
  2764.         token = lookahead;
  2765.         skipWhitespace();
  2766.  
  2767.         if (token.type === Token.EOF || token.type === Token.Punctuator) {
  2768.             throwUnexpected(token);
  2769.         }
  2770.  
  2771.         key = parseObjectPropertyKey();
  2772.         expect(':');
  2773.         return delegate.createProperty('init', key, parseExpression());
  2774.     }
  2775.  
  2776.     function parseObjectInitialiser() {
  2777.         var properties = [];
  2778.  
  2779.         expect('{');
  2780.  
  2781.         while (!match('}')) {
  2782.             properties.push(parseObjectProperty());
  2783.  
  2784.             if (!match('}')) {
  2785.                 expect(',');
  2786.             }
  2787.         }
  2788.  
  2789.         expect('}');
  2790.  
  2791.         return delegate.createObjectExpression(properties);
  2792.     }
  2793.  
  2794.     // 11.1.6 The Grouping Operator
  2795.  
  2796.     function parseGroupExpression() {
  2797.         var expr;
  2798.  
  2799.         expect('(');
  2800.  
  2801.         expr = parseExpression();
  2802.  
  2803.         expect(')');
  2804.  
  2805.         return expr;
  2806.     }
  2807.  
  2808.  
  2809.     // 11.1 Primary Expressions
  2810.  
  2811.     function parsePrimaryExpression() {
  2812.         var type, token, expr;
  2813.  
  2814.         if (match('(')) {
  2815.             return parseGroupExpression();
  2816.         }
  2817.  
  2818.         type = lookahead.type;
  2819.  
  2820.         if (type === Token.Identifier) {
  2821.             expr = delegate.createIdentifier(lex().value);
  2822.         } else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
  2823.             expr = delegate.createLiteral(lex());
  2824.         } else if (type === Token.Keyword) {
  2825.             if (matchKeyword('this')) {
  2826.                 lex();
  2827.                 expr = delegate.createThisExpression();
  2828.             }
  2829.         } else if (type === Token.BooleanLiteral) {
  2830.             token = lex();
  2831.             token.value = (token.value === 'true');
  2832.             expr = delegate.createLiteral(token);
  2833.         } else if (type === Token.NullLiteral) {
  2834.             token = lex();
  2835.             token.value = null;
  2836.             expr = delegate.createLiteral(token);
  2837.         } else if (match('[')) {
  2838.             expr = parseArrayInitialiser();
  2839.         } else if (match('{')) {
  2840.             expr = parseObjectInitialiser();
  2841.         }
  2842.  
  2843.         if (expr) {
  2844.             return expr;
  2845.         }
  2846.  
  2847.         throwUnexpected(lex());
  2848.     }
  2849.  
  2850.     // 11.2 Left-Hand-Side Expressions
  2851.  
  2852.     function parseArguments() {
  2853.         var args = [];
  2854.  
  2855.         expect('(');
  2856.  
  2857.         if (!match(')')) {
  2858.             while (index < length) {
  2859.                 args.push(parseExpression());
  2860.                 if (match(')')) {
  2861.                     break;
  2862.                 }
  2863.                 expect(',');
  2864.             }
  2865.         }
  2866.  
  2867.         expect(')');
  2868.  
  2869.         return args;
  2870.     }
  2871.  
  2872.     function parseNonComputedProperty() {
  2873.         var token;
  2874.  
  2875.         token = lex();
  2876.  
  2877.         if (!isIdentifierName(token)) {
  2878.             throwUnexpected(token);
  2879.         }
  2880.  
  2881.         return delegate.createIdentifier(token.value);
  2882.     }
  2883.  
  2884.     function parseNonComputedMember() {
  2885.         expect('.');
  2886.  
  2887.         return parseNonComputedProperty();
  2888.     }
  2889.  
  2890.     function parseComputedMember() {
  2891.         var expr;
  2892.  
  2893.         expect('[');
  2894.  
  2895.         expr = parseExpression();
  2896.  
  2897.         expect(']');
  2898.  
  2899.         return expr;
  2900.     }
  2901.  
  2902.     function parseLeftHandSideExpression() {
  2903.         var expr, args, property;
  2904.  
  2905.         expr = parsePrimaryExpression();
  2906.  
  2907.         while (true) {
  2908.             if (match('[')) {
  2909.                 property = parseComputedMember();
  2910.                 expr = delegate.createMemberExpression('[', expr, property);
  2911.             } else if (match('.')) {
  2912.                 property = parseNonComputedMember();
  2913.                 expr = delegate.createMemberExpression('.', expr, property);
  2914.             } else if (match('(')) {
  2915.                 args = parseArguments();
  2916.                 expr = delegate.createCallExpression(expr, args);
  2917.             } else {
  2918.                 break;
  2919.             }
  2920.         }
  2921.  
  2922.         return expr;
  2923.     }
  2924.  
  2925.     // 11.3 Postfix Expressions
  2926.  
  2927.     var parsePostfixExpression = parseLeftHandSideExpression;
  2928.  
  2929.     // 11.4 Unary Operators
  2930.  
  2931.     function parseUnaryExpression() {
  2932.         var token, expr;
  2933.  
  2934.         if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
  2935.             expr = parsePostfixExpression();
  2936.         } else if (match('+') || match('-') || match('!')) {
  2937.             token = lex();
  2938.             expr = parseUnaryExpression();
  2939.             expr = delegate.createUnaryExpression(token.value, expr);
  2940.         } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
  2941.             throwError({}, Messages.UnexpectedToken);
  2942.         } else {
  2943.             expr = parsePostfixExpression();
  2944.         }
  2945.  
  2946.         return expr;
  2947.     }
  2948.  
  2949.     function binaryPrecedence(token) {
  2950.         var prec = 0;
  2951.  
  2952.         if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
  2953.             return 0;
  2954.         }
  2955.  
  2956.         switch (token.value) {
  2957.         case '||':
  2958.             prec = 1;
  2959.             break;
  2960.  
  2961.         case '&&':
  2962.             prec = 2;
  2963.             break;
  2964.  
  2965.         case '==':
  2966.         case '!=':
  2967.         case '===':
  2968.         case '!==':
  2969.             prec = 6;
  2970.             break;
  2971.  
  2972.         case '<':
  2973.         case '>':
  2974.         case '<=':
  2975.         case '>=':
  2976.         case 'instanceof':
  2977.             prec = 7;
  2978.             break;
  2979.  
  2980.         case 'in':
  2981.             prec = 7;
  2982.             break;
  2983.  
  2984.         case '+':
  2985.         case '-':
  2986.             prec = 9;
  2987.             break;
  2988.  
  2989.         case '*':
  2990.         case '/':
  2991.         case '%':
  2992.             prec = 11;
  2993.             break;
  2994.  
  2995.         default:
  2996.             break;
  2997.         }
  2998.  
  2999.         return prec;
  3000.     }
  3001.  
  3002.     // 11.5 Multiplicative Operators
  3003.     // 11.6 Additive Operators
  3004.     // 11.7 Bitwise Shift Operators
  3005.     // 11.8 Relational Operators
  3006.     // 11.9 Equality Operators
  3007.     // 11.10 Binary Bitwise Operators
  3008.     // 11.11 Binary Logical Operators
  3009.  
  3010.     function parseBinaryExpression() {
  3011.         var expr, token, prec, stack, right, operator, left, i;
  3012.  
  3013.         left = parseUnaryExpression();
  3014.  
  3015.         token = lookahead;
  3016.         prec = binaryPrecedence(token);
  3017.         if (prec === 0) {
  3018.             return left;
  3019.         }
  3020.         token.prec = prec;
  3021.         lex();
  3022.  
  3023.         right = parseUnaryExpression();
  3024.  
  3025.         stack = [left, token, right];
  3026.  
  3027.         while ((prec = binaryPrecedence(lookahead)) > 0) {
  3028.  
  3029.             // Reduce: make a binary expression from the three topmost entries.
  3030.             while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
  3031.                 right = stack.pop();
  3032.                 operator = stack.pop().value;
  3033.                 left = stack.pop();
  3034.                 expr = delegate.createBinaryExpression(operator, left, right);
  3035.                 stack.push(expr);
  3036.             }
  3037.  
  3038.             // Shift.
  3039.             token = lex();
  3040.             token.prec = prec;
  3041.             stack.push(token);
  3042.             expr = parseUnaryExpression();
  3043.             stack.push(expr);
  3044.         }
  3045.  
  3046.         // Final reduce to clean-up the stack.
  3047.         i = stack.length - 1;
  3048.         expr = stack[i];
  3049.         while (i > 1) {
  3050.             expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
  3051.             i -= 2;
  3052.         }
  3053.  
  3054.         return expr;
  3055.     }
  3056.  
  3057.  
  3058.     // 11.12 Conditional Operator
  3059.  
  3060.     function parseConditionalExpression() {
  3061.         var expr, consequent, alternate;
  3062.  
  3063.         expr = parseBinaryExpression();
  3064.  
  3065.         if (match('?')) {
  3066.             lex();
  3067.             consequent = parseConditionalExpression();
  3068.             expect(':');
  3069.             alternate = parseConditionalExpression();
  3070.  
  3071.             expr = delegate.createConditionalExpression(expr, consequent, alternate);
  3072.         }
  3073.  
  3074.         return expr;
  3075.     }
  3076.  
  3077.     // Simplification since we do not support AssignmentExpression.
  3078.     var parseExpression = parseConditionalExpression;
  3079.  
  3080.     // Polymer Syntax extensions
  3081.  
  3082.     // Filter ::
  3083.     //   Identifier
  3084.     //   Identifier "(" ")"
  3085.     //   Identifier "(" FilterArguments ")"
  3086.  
  3087.     function parseFilter() {
  3088.         var identifier, args;
  3089.  
  3090.         identifier = lex();
  3091.  
  3092.         if (identifier.type !== Token.Identifier) {
  3093.             throwUnexpected(identifier);
  3094.         }
  3095.  
  3096.         args = match('(') ? parseArguments() : [];
  3097.  
  3098.         return delegate.createFilter(identifier.value, args);
  3099.     }
  3100.  
  3101.     // Filters ::
  3102.     //   "|" Filter
  3103.     //   Filters "|" Filter
  3104.  
  3105.     function parseFilters() {
  3106.         while (match('|')) {
  3107.             lex();
  3108.             parseFilter();
  3109.         }
  3110.     }
  3111.  
  3112.     // TopLevel ::
  3113.     //   LabelledExpressions
  3114.     //   AsExpression
  3115.     //   InExpression
  3116.     //   FilterExpression
  3117.  
  3118.     // AsExpression ::
  3119.     //   FilterExpression as Identifier
  3120.  
  3121.     // InExpression ::
  3122.     //   Identifier, Identifier in FilterExpression
  3123.     //   Identifier in FilterExpression
  3124.  
  3125.     // FilterExpression ::
  3126.     //   Expression
  3127.     //   Expression Filters
  3128.  
  3129.     function parseTopLevel() {
  3130.         skipWhitespace();
  3131.         peek();
  3132.  
  3133.         var expr = parseExpression();
  3134.         if (expr) {
  3135.             if (lookahead.value === ',' || lookahead.value == 'in' &&
  3136.                        expr.type === Syntax.Identifier) {
  3137.                 parseInExpression(expr);
  3138.             } else {
  3139.                 parseFilters();
  3140.                 if (lookahead.value === 'as') {
  3141.                     parseAsExpression(expr);
  3142.                 } else {
  3143.                     delegate.createTopLevel(expr);
  3144.                 }
  3145.             }
  3146.         }
  3147.  
  3148.         if (lookahead.type !== Token.EOF) {
  3149.             throwUnexpected(lookahead);
  3150.         }
  3151.     }
  3152.  
  3153.     function parseAsExpression(expr) {
  3154.         lex();  // as
  3155.         var identifier = lex().value;
  3156.         delegate.createAsExpression(expr, identifier);
  3157.     }
  3158.  
  3159.     function parseInExpression(identifier) {
  3160.         var indexName;
  3161.         if (lookahead.value === ',') {
  3162.             lex();
  3163.             if (lookahead.type !== Token.Identifier)
  3164.                 throwUnexpected(lookahead);
  3165.             indexName = lex().value;
  3166.         }
  3167.  
  3168.         lex();  // in
  3169.         var expr = parseExpression();
  3170.         parseFilters();
  3171.         delegate.createInExpression(identifier.name, indexName, expr);
  3172.     }
  3173.  
  3174.     function parse(code, inDelegate) {
  3175.         delegate = inDelegate;
  3176.         source = code;
  3177.         index = 0;
  3178.         length = source.length;
  3179.         lookahead = null;
  3180.         state = {
  3181.             labelSet: {}
  3182.         };
  3183.  
  3184.         return parseTopLevel();
  3185.     }
  3186.  
  3187.     global.esprima = {
  3188.         parse: parse
  3189.     };
  3190. })(this);
  3191.  
  3192. // Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
  3193. // This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
  3194. // The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
  3195. // The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
  3196. // Code distributed by Google as part of the polymer project is also
  3197. // subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
  3198.  
  3199. (function (global) {
  3200.   'use strict';
  3201.  
  3202.   function prepareBinding(expressionText, name, node, filterRegistry) {
  3203.     var expression;
  3204.     try {
  3205.       expression = getExpression(expressionText);
  3206.       if (expression.scopeIdent &&
  3207.           (node.nodeType !== Node.ELEMENT_NODE ||
  3208.            node.tagName !== 'TEMPLATE' ||
  3209.            (name !== 'bind' && name !== 'repeat'))) {
  3210.         throw Error('as and in can only be used within <template bind/repeat>');
  3211.       }
  3212.     } catch (ex) {
  3213.       console.error('Invalid expression syntax: ' + expressionText, ex);
  3214.       return;
  3215.     }
  3216.  
  3217.     return function(model, node, oneTime) {
  3218.       var binding = expression.getBinding(model, filterRegistry, oneTime);
  3219.       if (expression.scopeIdent && binding) {
  3220.         node.polymerExpressionScopeIdent_ = expression.scopeIdent;
  3221.         if (expression.indexIdent)
  3222.           node.polymerExpressionIndexIdent_ = expression.indexIdent;
  3223.       }
  3224.  
  3225.       return binding;
  3226.     }
  3227.   }
  3228.  
  3229.   // TODO(rafaelw): Implement simple LRU.
  3230.   var expressionParseCache = Object.create(null);
  3231.  
  3232.   function getExpression(expressionText) {
  3233.     var expression = expressionParseCache[expressionText];
  3234.     if (!expression) {
  3235.       var delegate = new ASTDelegate();
  3236.       esprima.parse(expressionText, delegate);
  3237.       expression = new Expression(delegate);
  3238.       expressionParseCache[expressionText] = expression;
  3239.     }
  3240.     return expression;
  3241.   }
  3242.  
  3243.   function Literal(value) {
  3244.     this.value = value;
  3245.     this.valueFn_ = undefined;
  3246.   }
  3247.  
  3248.   Literal.prototype = {
  3249.     valueFn: function() {
  3250.       if (!this.valueFn_) {
  3251.         var value = this.value;
  3252.         this.valueFn_ = function() {
  3253.           return value;
  3254.         }
  3255.       }
  3256.  
  3257.       return this.valueFn_;
  3258.     }
  3259.   }
  3260.  
  3261.   function IdentPath(name) {
  3262.     this.name = name;
  3263.     this.path = Path.get(name);
  3264.   }
  3265.  
  3266.   IdentPath.prototype = {
  3267.     valueFn: function() {
  3268.       if (!this.valueFn_) {
  3269.         var name = this.name;
  3270.         var path = this.path;
  3271.         this.valueFn_ = function(model, observer) {
  3272.           if (observer)
  3273.             observer.addPath(model, path);
  3274.  
  3275.           return path.getValueFrom(model);
  3276.         }
  3277.       }
  3278.  
  3279.       return this.valueFn_;
  3280.     },
  3281.  
  3282.     setValue: function(model, newValue) {
  3283.       if (this.path.length == 1)
  3284.         model = findScope(model, this.path[0]);
  3285.  
  3286.       return this.path.setValueFrom(model, newValue);
  3287.     }
  3288.   };
  3289.  
  3290.   function MemberExpression(object, property, accessor) {
  3291.     this.computed = accessor == '[';
  3292.  
  3293.     this.dynamicDeps = typeof object == 'function' ||
  3294.                        object.dynamicDeps ||
  3295.                        (this.computed && !(property instanceof Literal));
  3296.  
  3297.     this.simplePath =
  3298.         !this.dynamicDeps &&
  3299.         (property instanceof IdentPath || property instanceof Literal) &&
  3300.         (object instanceof MemberExpression || object instanceof IdentPath);
  3301.  
  3302.     this.object = this.simplePath ? object : getFn(object);
  3303.     this.property = !this.computed || this.simplePath ?
  3304.         property : getFn(property);
  3305.   }
  3306.  
  3307.   MemberExpression.prototype = {
  3308.     get fullPath() {
  3309.       if (!this.fullPath_) {
  3310.  
  3311.         var parts = this.object instanceof MemberExpression ?
  3312.             this.object.fullPath.slice() : [this.object.name];
  3313.         parts.push(this.property instanceof IdentPath ?
  3314.             this.property.name : this.property.value);
  3315.         this.fullPath_ = Path.get(parts);
  3316.       }
  3317.  
  3318.       return this.fullPath_;
  3319.     },
  3320.  
  3321.     valueFn: function() {
  3322.       if (!this.valueFn_) {
  3323.         var object = this.object;
  3324.  
  3325.         if (this.simplePath) {
  3326.           var path = this.fullPath;
  3327.  
  3328.           this.valueFn_ = function(model, observer) {
  3329.             if (observer)
  3330.               observer.addPath(model, path);
  3331.  
  3332.             return path.getValueFrom(model);
  3333.           };
  3334.         } else if (!this.computed) {
  3335.           var path = Path.get(this.property.name);
  3336.  
  3337.           this.valueFn_ = function(model, observer, filterRegistry) {
  3338.             var context = object(model, observer, filterRegistry);
  3339.  
  3340.             if (observer)
  3341.               observer.addPath(context, path);
  3342.  
  3343.             return path.getValueFrom(context);
  3344.           }
  3345.         } else {
  3346.           // Computed property.
  3347.           var property = this.property;
  3348.  
  3349.           this.valueFn_ = function(model, observer, filterRegistry) {
  3350.             var context = object(model, observer, filterRegistry);
  3351.             var propName = property(model, observer, filterRegistry);
  3352.             if (observer)
  3353.               observer.addPath(context, [propName]);
  3354.  
  3355.             return context ? context[propName] : undefined;
  3356.           };
  3357.         }
  3358.       }
  3359.       return this.valueFn_;
  3360.     },
  3361.  
  3362.     setValue: function(model, newValue) {
  3363.       if (this.simplePath) {
  3364.         this.fullPath.setValueFrom(model, newValue);
  3365.         return newValue;
  3366.       }
  3367.  
  3368.       var object = this.object(model);
  3369.       var propName = this.property instanceof IdentPath ? this.property.name :
  3370.           this.property(model);
  3371.       return object[propName] = newValue;
  3372.     }
  3373.   };
  3374.  
  3375.   function Filter(name, args) {
  3376.     this.name = name;
  3377.     this.args = [];
  3378.     for (var i = 0; i < args.length; i++) {
  3379.       this.args[i] = getFn(args[i]);
  3380.     }
  3381.   }
  3382.  
  3383.   Filter.prototype = {
  3384.     transform: function(model, observer, filterRegistry, toModelDirection,
  3385.                         initialArgs) {
  3386.       var fn = filterRegistry[this.name];
  3387.       var context = model;
  3388.       if (fn) {
  3389.         context = undefined;
  3390.       } else {
  3391.         fn = context[this.name];
  3392.         if (!fn) {
  3393.           console.error('Cannot find function or filter: ' + this.name);
  3394.           return;
  3395.         }
  3396.       }
  3397.  
  3398.       // If toModelDirection is falsey, then the "normal" (dom-bound) direction
  3399.       // is used. Otherwise, it looks for a 'toModel' property function on the
  3400.       // object.
  3401.       if (toModelDirection) {
  3402.         fn = fn.toModel;
  3403.       } else if (typeof fn.toDOM == 'function') {
  3404.         fn = fn.toDOM;
  3405.       }
  3406.  
  3407.       if (typeof fn != 'function') {
  3408.         console.error('Cannot find function or filter: ' + this.name);
  3409.         return;
  3410.       }
  3411.  
  3412.       var args = initialArgs || [];
  3413.       for (var i = 0; i < this.args.length; i++) {
  3414.         args.push(getFn(this.args[i])(model, observer, filterRegistry));
  3415.       }
  3416.  
  3417.       return fn.apply(context, args);
  3418.     }
  3419.   };
  3420.  
  3421.   function notImplemented() { throw Error('Not Implemented'); }
  3422.  
  3423.   var unaryOperators = {
  3424.     '+': function(v) { return +v; },
  3425.     '-': function(v) { return -v; },
  3426.     '!': function(v) { return !v; }
  3427.   };
  3428.  
  3429.   var binaryOperators = {
  3430.     '+': function(l, r) { return l+r; },
  3431.     '-': function(l, r) { return l-r; },
  3432.     '*': function(l, r) { return l*r; },
  3433.     '/': function(l, r) { return l/r; },
  3434.     '%': function(l, r) { return l%r; },
  3435.     '<': function(l, r) { return l<r; },
  3436.     '>': function(l, r) { return l>r; },
  3437.     '<=': function(l, r) { return l<=r; },
  3438.     '>=': function(l, r) { return l>=r; },
  3439.     '==': function(l, r) { return l==r; },
  3440.     '!=': function(l, r) { return l!=r; },
  3441.     '===': function(l, r) { return l===r; },
  3442.     '!==': function(l, r) { return l!==r; },
  3443.     '&&': function(l, r) { return l&&r; },
  3444.     '||': function(l, r) { return l||r; },
  3445.   };
  3446.  
  3447.   function getFn(arg) {
  3448.     return typeof arg == 'function' ? arg : arg.valueFn();
  3449.   }
  3450.  
  3451.   function ASTDelegate() {
  3452.     this.expression = null;
  3453.     this.filters = [];
  3454.     this.deps = {};
  3455.     this.currentPath = undefined;
  3456.     this.scopeIdent = undefined;
  3457.     this.indexIdent = undefined;
  3458.     this.dynamicDeps = false;
  3459.   }
  3460.  
  3461.   ASTDelegate.prototype = {
  3462.     createUnaryExpression: function(op, argument) {
  3463.       if (!unaryOperators[op])
  3464.         throw Error('Disallowed operator: ' + op);
  3465.  
  3466.       argument = getFn(argument);
  3467.  
  3468.       return function(model, observer, filterRegistry) {
  3469.         return unaryOperators[op](argument(model, observer, filterRegistry));
  3470.       };
  3471.     },
  3472.  
  3473.     createBinaryExpression: function(op, left, right) {
  3474.       if (!binaryOperators[op])
  3475.         throw Error('Disallowed operator: ' + op);
  3476.  
  3477.       left = getFn(left);
  3478.       right = getFn(right);
  3479.  
  3480.       switch (op) {
  3481.         case '||':
  3482.           this.dynamicDeps = true;
  3483.           return function(model, observer, filterRegistry) {
  3484.             return left(model, observer, filterRegistry) ||
  3485.                 right(model, observer, filterRegistry);
  3486.           };
  3487.         case '&&':
  3488.           this.dynamicDeps = true;
  3489.           return function(model, observer, filterRegistry) {
  3490.             return left(model, observer, filterRegistry) &&
  3491.                 right(model, observer, filterRegistry);
  3492.           };
  3493.       }
  3494.  
  3495.       return function(model, observer, filterRegistry) {
  3496.         return binaryOperators[op](left(model, observer, filterRegistry),
  3497.                                    right(model, observer, filterRegistry));
  3498.       };
  3499.     },
  3500.  
  3501.     createConditionalExpression: function(test, consequent, alternate) {
  3502.       test = getFn(test);
  3503.       consequent = getFn(consequent);
  3504.       alternate = getFn(alternate);
  3505.  
  3506.       this.dynamicDeps = true;
  3507.  
  3508.       return function(model, observer, filterRegistry) {
  3509.         return test(model, observer, filterRegistry) ?
  3510.             consequent(model, observer, filterRegistry) :
  3511.             alternate(model, observer, filterRegistry);
  3512.       }
  3513.     },
  3514.  
  3515.     createIdentifier: function(name) {
  3516.       var ident = new IdentPath(name);
  3517.       ident.type = 'Identifier';
  3518.       return ident;
  3519.     },
  3520.  
  3521.     createMemberExpression: function(accessor, object, property) {
  3522.       var ex = new MemberExpression(object, property, accessor);
  3523.       if (ex.dynamicDeps)
  3524.         this.dynamicDeps = true;
  3525.       return ex;
  3526.     },
  3527.  
  3528.     createCallExpression: function(expression, args) {
  3529.       if (!(expression instanceof IdentPath))
  3530.         throw Error('Only identifier function invocations are allowed');
  3531.  
  3532.       var filter = new Filter(expression.name, args);
  3533.  
  3534.       return function(model, observer, filterRegistry) {
  3535.         return filter.transform(model, observer, filterRegistry, false);
  3536.       };
  3537.     },
  3538.  
  3539.     createLiteral: function(token) {
  3540.       return new Literal(token.value);
  3541.     },
  3542.  
  3543.     createArrayExpression: function(elements) {
  3544.       for (var i = 0; i < elements.length; i++)
  3545.         elements[i] = getFn(elements[i]);
  3546.  
  3547.       return function(model, observer, filterRegistry) {
  3548.         var arr = []
  3549.         for (var i = 0; i < elements.length; i++)
  3550.           arr.push(elements[i](model, observer, filterRegistry));
  3551.         return arr;
  3552.       }
  3553.     },
  3554.  
  3555.     createProperty: function(kind, key, value) {
  3556.       return {
  3557.         key: key instanceof IdentPath ? key.name : key.value,
  3558.         value: value
  3559.       };
  3560.     },
  3561.  
  3562.     createObjectExpression: function(properties) {
  3563.       for (var i = 0; i < properties.length; i++)
  3564.         properties[i].value = getFn(properties[i].value);
  3565.  
  3566.       return function(model, observer, filterRegistry) {
  3567.         var obj = {};
  3568.         for (var i = 0; i < properties.length; i++)
  3569.           obj[properties[i].key] =
  3570.               properties[i].value(model, observer, filterRegistry);
  3571.         return obj;
  3572.       }
  3573.     },
  3574.  
  3575.     createFilter: function(name, args) {
  3576.       this.filters.push(new Filter(name, args));
  3577.     },
  3578.  
  3579.     createAsExpression: function(expression, scopeIdent) {
  3580.       this.expression = expression;
  3581.       this.scopeIdent = scopeIdent;
  3582.     },
  3583.  
  3584.     createInExpression: function(scopeIdent, indexIdent, expression) {
  3585.       this.expression = expression;
  3586.       this.scopeIdent = scopeIdent;
  3587.       this.indexIdent = indexIdent;
  3588.     },
  3589.  
  3590.     createTopLevel: function(expression) {
  3591.       this.expression = expression;
  3592.     },
  3593.  
  3594.     createThisExpression: notImplemented
  3595.   }
  3596.  
  3597.   function ConstantObservable(value) {
  3598.     this.value_ = value;
  3599.   }
  3600.  
  3601.   ConstantObservable.prototype = {
  3602.     open: function() { return this.value_; },
  3603.     discardChanges: function() { return this.value_; },
  3604.     deliver: function() {},
  3605.     close: function() {},
  3606.   }
  3607.  
  3608.   function Expression(delegate) {
  3609.     this.scopeIdent = delegate.scopeIdent;
  3610.     this.indexIdent = delegate.indexIdent;
  3611.  
  3612.     if (!delegate.expression)
  3613.       throw Error('No expression found.');
  3614.  
  3615.     this.expression = delegate.expression;
  3616.     getFn(this.expression); // forces enumeration of path dependencies
  3617.  
  3618.     this.filters = delegate.filters;
  3619.     this.dynamicDeps = delegate.dynamicDeps;
  3620.   }
  3621.  
  3622.   Expression.prototype = {
  3623.     getBinding: function(model, filterRegistry, oneTime) {
  3624.       if (oneTime)
  3625.         return this.getValue(model, undefined, filterRegistry);
  3626.  
  3627.       var observer = new CompoundObserver();
  3628.       // captures deps.
  3629.       var firstValue = this.getValue(model, observer, filterRegistry);
  3630.       var firstTime = true;
  3631.       var self = this;
  3632.  
  3633.       function valueFn() {
  3634.         // deps cannot have changed on first value retrieval.
  3635.         if (firstTime) {
  3636.           firstTime = false;
  3637.           return firstValue;
  3638.         }
  3639.  
  3640.         if (self.dynamicDeps)
  3641.           observer.startReset();
  3642.  
  3643.         var value = self.getValue(model,
  3644.                                   self.dynamicDeps ? observer : undefined,
  3645.                                   filterRegistry);
  3646.         if (self.dynamicDeps)
  3647.           observer.finishReset();
  3648.  
  3649.         return value;
  3650.       }
  3651.  
  3652.       function setValueFn(newValue) {
  3653.         self.setValue(model, newValue, filterRegistry);
  3654.         return newValue;
  3655.       }
  3656.  
  3657.       return new ObserverTransform(observer, valueFn, setValueFn, true);
  3658.     },
  3659.  
  3660.     getValue: function(model, observer, filterRegistry) {
  3661.       var value = getFn(this.expression)(model, observer, filterRegistry);
  3662.       for (var i = 0; i < this.filters.length; i++) {
  3663.         value = this.filters[i].transform(model, observer, filterRegistry,
  3664.             false, [value]);
  3665.       }
  3666.  
  3667.       return value;
  3668.     },
  3669.  
  3670.     setValue: function(model, newValue, filterRegistry) {
  3671.       var count = this.filters ? this.filters.length : 0;
  3672.       while (count-- > 0) {
  3673.         newValue = this.filters[count].transform(model, undefined,
  3674.             filterRegistry, true, [newValue]);
  3675.       }
  3676.  
  3677.       if (this.expression.setValue)
  3678.         return this.expression.setValue(model, newValue);
  3679.     }
  3680.   }
  3681.  
  3682.   /**
  3683.    * Converts a style property name to a css property name. For example:
  3684.    * "WebkitUserSelect" to "-webkit-user-select"
  3685.    */
  3686.   function convertStylePropertyName(name) {
  3687.     return String(name).replace(/[A-Z]/g, function(c) {
  3688.       return '-' + c.toLowerCase();
  3689.     });
  3690.   }
  3691.  
  3692.   var parentScopeName = '@' + Math.random().toString(36).slice(2);
  3693.  
  3694.   // Single ident paths must bind directly to the appropriate scope object.
  3695.   // I.e. Pushed values in two-bindings need to be assigned to the actual model
  3696.   // object.
  3697.   function findScope(model, prop) {
  3698.     while (model[parentScopeName] &&
  3699.            !Object.prototype.hasOwnProperty.call(model, prop)) {
  3700.       model = model[parentScopeName];
  3701.     }
  3702.  
  3703.     return model;
  3704.   }
  3705.  
  3706.   function isLiteralExpression(pathString) {
  3707.     switch (pathString) {
  3708.       case '':
  3709.         return false;
  3710.  
  3711.       case 'false':
  3712.       case 'null':
  3713.       case 'true':
  3714.         return true;
  3715.     }
  3716.  
  3717.     if (!isNaN(Number(pathString)))
  3718.       return true;
  3719.  
  3720.     return false;
  3721.   };
  3722.  
  3723.   function PolymerExpressions() {}
  3724.  
  3725.   PolymerExpressions.prototype = {
  3726.     // "built-in" filters
  3727.     styleObject: function(value) {
  3728.       var parts = [];
  3729.       for (var key in value) {
  3730.         parts.push(convertStylePropertyName(key) + ': ' + value[key]);
  3731.       }
  3732.       return parts.join('; ');
  3733.     },
  3734.  
  3735.     tokenList: function(value) {
  3736.       var tokens = [];
  3737.       for (var key in value) {
  3738.         if (value[key])
  3739.           tokens.push(key);
  3740.       }
  3741.       return tokens.join(' ');
  3742.     },
  3743.  
  3744.     // binding delegate API
  3745.     prepareInstancePositionChanged: function(template) {
  3746.       var indexIdent = template.polymerExpressionIndexIdent_;
  3747.       if (!indexIdent)
  3748.         return;
  3749.  
  3750.       return function(templateInstance, index) {
  3751.         templateInstance.model[indexIdent] = index;
  3752.       };
  3753.     },
  3754.  
  3755.     prepareBinding: function(pathString, name, node) {
  3756.       var path = Path.get(pathString);
  3757.  
  3758.       if (!isLiteralExpression(pathString) && path.valid) {
  3759.         if (path.length == 1) {
  3760.           return function(model, node, oneTime) {
  3761.             if (oneTime)
  3762.               return path.getValueFrom(model);
  3763.  
  3764.             var scope = findScope(model, path[0]);
  3765.             return new PathObserver(scope, path);
  3766.           };
  3767.         }
  3768.         return; // bail out early if pathString is simple path.
  3769.       }
  3770.  
  3771.       return prepareBinding(pathString, name, node, this);
  3772.     },
  3773.  
  3774.     prepareInstanceModel: function(template) {
  3775.       var scopeName = template.polymerExpressionScopeIdent_;
  3776.       if (!scopeName)
  3777.         return;
  3778.  
  3779.       var parentScope = template.templateInstance ?
  3780.           template.templateInstance.model :
  3781.           template.model;
  3782.  
  3783.       var indexName = template.polymerExpressionIndexIdent_;
  3784.  
  3785.       return function(model) {
  3786.         return createScopeObject(parentScope, model, scopeName, indexName);
  3787.       };
  3788.     }
  3789.   };
  3790.  
  3791.   var createScopeObject = ('__proto__' in {}) ?
  3792.     function(parentScope, model, scopeName, indexName) {
  3793.       var scope = {};
  3794.       scope[scopeName] = model;
  3795.       scope[indexName] = undefined;
  3796.       scope[parentScopeName] = parentScope;
  3797.       scope.__proto__ = parentScope;
  3798.       return scope;
  3799.     } :
  3800.     function(parentScope, model, scopeName, indexName) {
  3801.       var scope = Object.create(parentScope);
  3802.       Object.defineProperty(scope, scopeName,
  3803.           { value: model, configurable: true, writable: true });
  3804.       Object.defineProperty(scope, indexName,
  3805.           { value: undefined, configurable: true, writable: true });
  3806.       Object.defineProperty(scope, parentScopeName,
  3807.           { value: parentScope, configurable: true, writable: true });
  3808.       return scope;
  3809.     };
  3810.  
  3811.   global.PolymerExpressions = PolymerExpressions;
  3812.   PolymerExpressions.getExpression = getExpression;
  3813. })(this);
  3814.  
  3815. Polymer = {
  3816.   version: '0.5.1'
  3817. };
  3818.  
  3819. // TODO(sorvell): this ensures Polymer is an object and not a function
  3820. // Platform is currently defining it as a function to allow for async loading
  3821. // of polymer; once we refine the loading process this likely goes away.
  3822. if (typeof window.Polymer === 'function') {
  3823.   Polymer = {};
  3824. }
  3825.  
  3826.  
  3827. (function(scope) {
  3828.  
  3829.   function withDependencies(task, depends) {
  3830.     depends = depends || [];
  3831.     if (!depends.map) {
  3832.       depends = [depends];
  3833.     }
  3834.     return task.apply(this, depends.map(marshal));
  3835.   }
  3836.  
  3837.   function module(name, dependsOrFactory, moduleFactory) {
  3838.     var module;
  3839.     switch (arguments.length) {
  3840.       case 0:
  3841.         return;
  3842.       case 1:
  3843.         module = null;
  3844.         break;
  3845.       case 2:
  3846.         // dependsOrFactory is `factory` in this case
  3847.         module = dependsOrFactory.apply(this);
  3848.         break;
  3849.       default:
  3850.         // dependsOrFactory is `depends` in this case
  3851.         module = withDependencies(moduleFactory, dependsOrFactory);
  3852.         break;
  3853.     }
  3854.     modules[name] = module;
  3855.   };
  3856.  
  3857.   function marshal(name) {
  3858.     return modules[name];
  3859.   }
  3860.  
  3861.   var modules = {};
  3862.  
  3863.   function using(depends, task) {
  3864.     HTMLImports.whenImportsReady(function() {
  3865.       withDependencies(task, depends);
  3866.     });
  3867.   };
  3868.  
  3869.   // exports
  3870.  
  3871.   scope.marshal = marshal;
  3872.   // `module` confuses commonjs detectors
  3873.   scope.modularize = module;
  3874.   scope.using = using;
  3875.  
  3876. })(window);
  3877.  
  3878. /*
  3879.     Build only script.
  3880.  
  3881.   Ensures scripts needed for basic x-platform compatibility
  3882.   will be run when platform.js is not loaded.
  3883.  */
  3884. if (!window.WebComponents) {
  3885.  
  3886. /*
  3887.     On supported platforms, platform.js is not needed. To retain compatibility
  3888.     with the polyfills, we stub out minimal functionality.
  3889.  */
  3890. if (!window.WebComponents) {
  3891.  
  3892.   WebComponents = {
  3893.       flush: function() {},
  3894.     flags: {log: {}}
  3895.   };
  3896.  
  3897.   Platform = WebComponents;
  3898.  
  3899.   CustomElements = {
  3900.       useNative: true,
  3901.     ready: true,
  3902.     takeRecords: function() {},
  3903.     instanceof: function(obj, base) {
  3904.       return obj instanceof base;
  3905.     }
  3906.   };
  3907.   
  3908.   HTMLImports = {
  3909.       useNative: true
  3910.   };
  3911.  
  3912.   
  3913.   addEventListener('HTMLImportsLoaded', function() {
  3914.     document.dispatchEvent(
  3915.       new CustomEvent('WebComponentsReady', {bubbles: true})
  3916.     );
  3917.   });
  3918.  
  3919.  
  3920.   // ShadowDOM
  3921.   ShadowDOMPolyfill = null;
  3922.   wrap = unwrap = function(n){
  3923.     return n;
  3924.   };
  3925.  
  3926. }
  3927.  
  3928. /*
  3929.   Create polyfill scope and feature detect native support.
  3930. */
  3931. window.HTMLImports = window.HTMLImports || {flags:{}};
  3932.  
  3933. (function(scope) {
  3934.  
  3935. /**
  3936.   Basic setup and simple module executer. We collect modules and then execute
  3937.   the code later, only if it's necessary for polyfilling.
  3938. */
  3939. var IMPORT_LINK_TYPE = 'import';
  3940. var useNative = Boolean(IMPORT_LINK_TYPE in document.createElement('link'));
  3941.  
  3942. /**
  3943.   Support `currentScript` on all browsers as `document._currentScript.`
  3944.  
  3945.   NOTE: We cannot polyfill `document.currentScript` because it's not possible
  3946.   both to override and maintain the ability to capture the native value.
  3947.   Therefore we choose to expose `_currentScript` both when native imports
  3948.   and the polyfill are in use.
  3949. */
  3950. // NOTE: ShadowDOMPolyfill intrusion.
  3951. var hasShadowDOMPolyfill = Boolean(window.ShadowDOMPolyfill);
  3952. var wrap = function(node) {
  3953.   return hasShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node) : node;
  3954. };
  3955. var rootDocument = wrap(document);
  3956.  
  3957. var currentScriptDescriptor = {
  3958.   get: function() {
  3959.     var script = HTMLImports.currentScript || document.currentScript ||
  3960.         // NOTE: only works when called in synchronously executing code.
  3961.         // readyState should check if `loading` but IE10 is
  3962.         // interactive when scripts run so we cheat.
  3963.         (document.readyState !== 'complete' ?
  3964.         document.scripts[document.scripts.length - 1] : null);
  3965.     return wrap(script);
  3966.   },
  3967.   configurable: true
  3968. };
  3969.  
  3970. Object.defineProperty(document, '_currentScript', currentScriptDescriptor);
  3971. Object.defineProperty(rootDocument, '_currentScript', currentScriptDescriptor);
  3972.  
  3973. /**
  3974.   Add support for the `HTMLImportsLoaded` event and the `HTMLImports.whenReady`
  3975.   method. This api is necessary because unlike the native implementation,
  3976.   script elements do not force imports to resolve. Instead, users should wrap
  3977.   code in either an `HTMLImportsLoaded` hander or after load time in an
  3978.   `HTMLImports.whenReady(callback)` call.
  3979.  
  3980.   NOTE: This module also supports these apis under the native implementation.
  3981.   Therefore, if this file is loaded, the same code can be used under both
  3982.   the polyfill and native implementation.
  3983.  */
  3984.  
  3985. var isIE = /Trident/.test(navigator.userAgent);
  3986.  
  3987. // call a callback when all HTMLImports in the document at call time
  3988. // (or at least document ready) have loaded.
  3989. // 1. ensure the document is in a ready state (has dom), then
  3990. // 2. watch for loading of imports and call callback when done
  3991. function whenReady(callback, doc) {
  3992.   doc = doc || rootDocument;
  3993.   // if document is loading, wait and try again
  3994.   whenDocumentReady(function() {
  3995.     watchImportsLoad(callback, doc);
  3996.   }, doc);
  3997. }
  3998.  
  3999. // call the callback when the document is in a ready state (has dom)
  4000. var requiredReadyState = isIE ? 'complete' : 'interactive';
  4001. var READY_EVENT = 'readystatechange';
  4002. function isDocumentReady(doc) {
  4003.   return (doc.readyState === 'complete' ||
  4004.       doc.readyState === requiredReadyState);
  4005. }
  4006.  
  4007. // call <callback> when we ensure the document is in a ready state
  4008. function whenDocumentReady(callback, doc) {
  4009.   if (!isDocumentReady(doc)) {
  4010.     var checkReady = function() {
  4011.       if (doc.readyState === 'complete' ||
  4012.           doc.readyState === requiredReadyState) {
  4013.         doc.removeEventListener(READY_EVENT, checkReady);
  4014.         whenDocumentReady(callback, doc);
  4015.       }
  4016.     };
  4017.     doc.addEventListener(READY_EVENT, checkReady);
  4018.   } else if (callback) {
  4019.     callback();
  4020.   }
  4021. }
  4022.  
  4023. function markTargetLoaded(event) {
  4024.   event.target.__loaded = true;
  4025. }
  4026.  
  4027. // call <callback> when we ensure all imports have loaded
  4028. function watchImportsLoad(callback, doc) {
  4029.   var imports = doc.querySelectorAll('link[rel=import]');
  4030.   var loaded = 0, l = imports.length;
  4031.   function checkDone(d) {
  4032.     if ((loaded == l) && callback) {
  4033.        callback();
  4034.     }
  4035.   }
  4036.   function loadedImport(e) {
  4037.     markTargetLoaded(e);
  4038.     loaded++;
  4039.     checkDone();
  4040.   }
  4041.   if (l) {
  4042.     for (var i=0, imp; (i<l) && (imp=imports[i]); i++) {
  4043.       if (isImportLoaded(imp)) {
  4044.         loadedImport.call(imp, {target: imp});
  4045.       } else {
  4046.         imp.addEventListener('load', loadedImport);
  4047.         imp.addEventListener('error', loadedImport);
  4048.       }
  4049.     }
  4050.   } else {
  4051.     checkDone();
  4052.   }
  4053. }
  4054.  
  4055. // NOTE: test for native imports loading is based on explicitly watching
  4056. // all imports (see below).
  4057. // However, we cannot rely on this entirely without watching the entire document
  4058. // for import links. For perf reasons, currently only head is watched.
  4059. // Instead, we fallback to checking if the import property is available
  4060. // and the document is not itself loading.
  4061. function isImportLoaded(link) {
  4062.   return useNative ? link.__loaded ||
  4063.       (link.import && link.import.readyState !== 'loading') :
  4064.       link.__importParsed;
  4065. }
  4066.  
  4067. // TODO(sorvell): Workaround for
  4068. // https://www.w3.org/Bugs/Public/show_bug.cgi?id=25007, should be removed when
  4069. // this bug is addressed.
  4070. // (1) Install a mutation observer to see when HTMLImports have loaded
  4071. // (2) if this script is run during document load it will watch any existing
  4072. // imports for loading.
  4073. //
  4074. // NOTE: The workaround has restricted functionality: (1) it's only compatible
  4075. // with imports that are added to document.head since the mutation observer
  4076. // watches only head for perf reasons, (2) it requires this script
  4077. // to run before any imports have completed loading.
  4078. if (useNative) {
  4079.   new MutationObserver(function(mxns) {
  4080.     for (var i=0, l=mxns.length, m; (i < l) && (m=mxns[i]); i++) {
  4081.       if (m.addedNodes) {
  4082.         handleImports(m.addedNodes);
  4083.       }
  4084.     }
  4085.   }).observe(document.head, {childList: true});
  4086.  
  4087.   function handleImports(nodes) {
  4088.     for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) {
  4089.       if (isImport(n)) {
  4090.         handleImport(n);
  4091.       }
  4092.     }
  4093.   }
  4094.  
  4095.   function isImport(element) {
  4096.     return element.localName === 'link' && element.rel === 'import';
  4097.   }
  4098.  
  4099.   function handleImport(element) {
  4100.     var loaded = element.import;
  4101.     if (loaded) {
  4102.       markTargetLoaded({target: element});
  4103.     } else {
  4104.       element.addEventListener('load', markTargetLoaded);
  4105.       element.addEventListener('error', markTargetLoaded);
  4106.     }
  4107.   }
  4108.  
  4109.   // make sure to catch any imports that are in the process of loading
  4110.   // when this script is run.
  4111.   (function() {
  4112.     if (document.readyState === 'loading') {
  4113.       var imports = document.querySelectorAll('link[rel=import]');
  4114.       for (var i=0, l=imports.length, imp; (i<l) && (imp=imports[i]); i++) {
  4115.         handleImport(imp);
  4116.       }
  4117.     }
  4118.   })();
  4119.  
  4120. }
  4121.  
  4122. // Fire the 'HTMLImportsLoaded' event when imports in document at load time
  4123. // have loaded. This event is required to simulate the script blocking
  4124. // behavior of native imports. A main document script that needs to be sure
  4125. // imports have loaded should wait for this event.
  4126. whenReady(function() {
  4127.   HTMLImports.ready = true;
  4128.   HTMLImports.readyTime = new Date().getTime();
  4129.   rootDocument.dispatchEvent(
  4130.     new CustomEvent('HTMLImportsLoaded', {bubbles: true})
  4131.   );
  4132. });
  4133.  
  4134. // exports
  4135. scope.IMPORT_LINK_TYPE = IMPORT_LINK_TYPE;
  4136. scope.useNative = useNative;
  4137. scope.rootDocument = rootDocument;
  4138. scope.whenReady = whenReady;
  4139. scope.isIE = isIE;
  4140.  
  4141. })(HTMLImports);
  4142.  
  4143. (function(scope) {
  4144.  
  4145.   // TODO(sorvell): It's desireable to provide a default stylesheet 
  4146.   // that's convenient for styling unresolved elements, but
  4147.   // it's cumbersome to have to include this manually in every page.
  4148.   // It would make sense to put inside some HTMLImport but 
  4149.   // the HTMLImports polyfill does not allow loading of stylesheets 
  4150.   // that block rendering. Therefore this injection is tolerated here.
  4151.   var style = document.createElement('style');
  4152.   style.textContent = ''
  4153.       + 'body {'
  4154.       + 'transition: opacity ease-in 0.2s;' 
  4155.       + ' } \n'
  4156.       + 'body[unresolved] {'
  4157.       + 'opacity: 0; display: block; overflow: hidden;' 
  4158.       + ' } \n'
  4159.       ;
  4160.   var head = document.querySelector('head');
  4161.   head.insertBefore(style, head.firstChild);
  4162.  
  4163. })(Platform);
  4164.  
  4165. /*
  4166.     Build only script.
  4167.  
  4168.   Ensures scripts needed for basic x-platform compatibility
  4169.   will be run when platform.js is not loaded.
  4170.  */
  4171. }
  4172. (function(global) {
  4173.   'use strict';
  4174.  
  4175.   var testingExposeCycleCount = global.testingExposeCycleCount;
  4176.  
  4177.   // Detect and do basic sanity checking on Object/Array.observe.
  4178.   function detectObjectObserve() {
  4179.     if (typeof Object.observe !== 'function' ||
  4180.         typeof Array.observe !== 'function') {
  4181.       return false;
  4182.     }
  4183.  
  4184.     var records = [];
  4185.  
  4186.     function callback(recs) {
  4187.       records = recs;
  4188.     }
  4189.  
  4190.     var test = {};
  4191.     var arr = [];
  4192.     Object.observe(test, callback);
  4193.     Array.observe(arr, callback);
  4194.     test.id = 1;
  4195.     test.id = 2;
  4196.     delete test.id;
  4197.     arr.push(1, 2);
  4198.     arr.length = 0;
  4199.  
  4200.     Object.deliverChangeRecords(callback);
  4201.     if (records.length !== 5)
  4202.       return false;
  4203.  
  4204.     if (records[0].type != 'add' ||
  4205.         records[1].type != 'update' ||
  4206.         records[2].type != 'delete' ||
  4207.         records[3].type != 'splice' ||
  4208.         records[4].type != 'splice') {
  4209.       return false;
  4210.     }
  4211.  
  4212.     Object.unobserve(test, callback);
  4213.     Array.unobserve(arr, callback);
  4214.  
  4215.     return true;
  4216.   }
  4217.  
  4218.   var hasObserve = detectObjectObserve();
  4219.  
  4220.   function detectEval() {
  4221.     // Don't test for eval if we're running in a Chrome App environment.
  4222.     // We check for APIs set that only exist in a Chrome App context.
  4223.     if (typeof chrome !== 'undefined' && chrome.app && chrome.app.runtime) {
  4224.       return false;
  4225.     }
  4226.  
  4227.     // Firefox OS Apps do not allow eval. This feature detection is very hacky
  4228.     // but even if some other platform adds support for this function this code
  4229.     // will continue to work.
  4230.     if (typeof navigator != 'undefined' && navigator.getDeviceStorage) {
  4231.       return false;
  4232.     }
  4233.  
  4234.     try {
  4235.       var f = new Function('', 'return true;');
  4236.       return f();
  4237.     } catch (ex) {
  4238.       return false;
  4239.     }
  4240.   }
  4241.  
  4242.   var hasEval = detectEval();
  4243.  
  4244.   function isIndex(s) {
  4245.     return +s === s >>> 0 && s !== '';
  4246.   }
  4247.  
  4248.   function toNumber(s) {
  4249.     return +s;
  4250.   }
  4251.  
  4252.   function isObject(obj) {
  4253.     return obj === Object(obj);
  4254.   }
  4255.  
  4256.   var numberIsNaN = global.Number.isNaN || function(value) {
  4257.     return typeof value === 'number' && global.isNaN(value);
  4258.   }
  4259.  
  4260.   function areSameValue(left, right) {
  4261.     if (left === right)
  4262.       return left !== 0 || 1 / left === 1 / right;
  4263.     if (numberIsNaN(left) && numberIsNaN(right))
  4264.       return true;
  4265.  
  4266.     return left !== left && right !== right;
  4267.   }
  4268.  
  4269.   var createObject = ('__proto__' in {}) ?
  4270.     function(obj) { return obj; } :
  4271.     function(obj) {
  4272.       var proto = obj.__proto__;
  4273.       if (!proto)
  4274.         return obj;
  4275.       var newObject = Object.create(proto);
  4276.       Object.getOwnPropertyNames(obj).forEach(function(name) {
  4277.         Object.defineProperty(newObject, name,
  4278.                              Object.getOwnPropertyDescriptor(obj, name));
  4279.       });
  4280.       return newObject;
  4281.     };
  4282.  
  4283.   var identStart = '[\$_a-zA-Z]';
  4284.   var identPart = '[\$_a-zA-Z0-9]';
  4285.   var identRegExp = new RegExp('^' + identStart + '+' + identPart + '*' + '$');
  4286.  
  4287.   function getPathCharType(char) {
  4288.     if (char === undefined)
  4289.       return 'eof';
  4290.  
  4291.     var code = char.charCodeAt(0);
  4292.  
  4293.     switch(code) {
  4294.       case 0x5B: // [
  4295.       case 0x5D: // ]
  4296.       case 0x2E: // .
  4297.       case 0x22: // "
  4298.       case 0x27: // '
  4299.       case 0x30: // 0
  4300.         return char;
  4301.  
  4302.       case 0x5F: // _
  4303.       case 0x24: // $
  4304.         return 'ident';
  4305.  
  4306.       case 0x20: // Space
  4307.       case 0x09: // Tab
  4308.       case 0x0A: // Newline
  4309.       case 0x0D: // Return
  4310.       case 0xA0:  // No-break space
  4311.       case 0xFEFF:  // Byte Order Mark
  4312.       case 0x2028:  // Line Separator
  4313.       case 0x2029:  // Paragraph Separator
  4314.         return 'ws';
  4315.     }
  4316.  
  4317.     // a-z, A-Z
  4318.     if ((0x61 <= code && code <= 0x7A) || (0x41 <= code && code <= 0x5A))
  4319.       return 'ident';
  4320.  
  4321.     // 1-9
  4322.     if (0x31 <= code && code <= 0x39)
  4323.       return 'number';
  4324.  
  4325.     return 'else';
  4326.   }
  4327.  
  4328.   var pathStateMachine = {
  4329.     'beforePath': {
  4330.       'ws': ['beforePath'],
  4331.       'ident': ['inIdent', 'append'],
  4332.       '[': ['beforeElement'],
  4333.       'eof': ['afterPath']
  4334.     },
  4335.  
  4336.     'inPath': {
  4337.       'ws': ['inPath'],
  4338.       '.': ['beforeIdent'],
  4339.       '[': ['beforeElement'],
  4340.       'eof': ['afterPath']
  4341.     },
  4342.  
  4343.     'beforeIdent': {
  4344.       'ws': ['beforeIdent'],
  4345.       'ident': ['inIdent', 'append']
  4346.     },
  4347.  
  4348.     'inIdent': {
  4349.       'ident': ['inIdent', 'append'],
  4350.       '0': ['inIdent', 'append'],
  4351.       'number': ['inIdent', 'append'],
  4352.       'ws': ['inPath', 'push'],
  4353.       '.': ['beforeIdent', 'push'],
  4354.       '[': ['beforeElement', 'push'],
  4355.       'eof': ['afterPath', 'push']
  4356.     },
  4357.  
  4358.     'beforeElement': {
  4359.       'ws': ['beforeElement'],
  4360.       '0': ['afterZero', 'append'],
  4361.       'number': ['inIndex', 'append'],
  4362.       "'": ['inSingleQuote', 'append', ''],
  4363.       '"': ['inDoubleQuote', 'append', '']
  4364.     },
  4365.  
  4366.     'afterZero': {
  4367.       'ws': ['afterElement', 'push'],
  4368.       ']': ['inPath', 'push']
  4369.     },
  4370.  
  4371.     'inIndex': {
  4372.       '0': ['inIndex', 'append'],
  4373.       'number': ['inIndex', 'append'],
  4374.       'ws': ['afterElement'],
  4375.       ']': ['inPath', 'push']
  4376.     },
  4377.  
  4378.     'inSingleQuote': {
  4379.       "'": ['afterElement'],
  4380.       'eof': ['error'],
  4381.       'else': ['inSingleQuote', 'append']
  4382.     },
  4383.  
  4384.     'inDoubleQuote': {
  4385.       '"': ['afterElement'],
  4386.       'eof': ['error'],
  4387.       'else': ['inDoubleQuote', 'append']
  4388.     },
  4389.  
  4390.     'afterElement': {
  4391.       'ws': ['afterElement'],
  4392.       ']': ['inPath', 'push']
  4393.     }
  4394.   }
  4395.  
  4396.   function noop() {}
  4397.  
  4398.   function parsePath(path) {
  4399.     var keys = [];
  4400.     var index = -1;
  4401.     var c, newChar, key, type, transition, action, typeMap, mode = 'beforePath';
  4402.  
  4403.     var actions = {
  4404.       push: function() {
  4405.         if (key === undefined)
  4406.           return;
  4407.  
  4408.         keys.push(key);
  4409.         key = undefined;
  4410.       },
  4411.  
  4412.       append: function() {
  4413.         if (key === undefined)
  4414.           key = newChar
  4415.         else
  4416.           key += newChar;
  4417.       }
  4418.     };
  4419.  
  4420.     function maybeUnescapeQuote() {
  4421.       if (index >= path.length)
  4422.         return;
  4423.  
  4424.       var nextChar = path[index + 1];
  4425.       if ((mode == 'inSingleQuote' && nextChar == "'") ||
  4426.           (mode == 'inDoubleQuote' && nextChar == '"')) {
  4427.         index++;
  4428.         newChar = nextChar;
  4429.         actions.append();
  4430.         return true;
  4431.       }
  4432.     }
  4433.  
  4434.     while (mode) {
  4435.       index++;
  4436.       c = path[index];
  4437.  
  4438.       if (c == '\\' && maybeUnescapeQuote(mode))
  4439.         continue;
  4440.  
  4441.       type = getPathCharType(c);
  4442.       typeMap = pathStateMachine[mode];
  4443.       transition = typeMap[type] || typeMap['else'] || 'error';
  4444.  
  4445.       if (transition == 'error')
  4446.         return; // parse error;
  4447.  
  4448.       mode = transition[0];
  4449.       action = actions[transition[1]] || noop;
  4450.       newChar = transition[2] === undefined ? c : transition[2];
  4451.       action();
  4452.  
  4453.       if (mode === 'afterPath') {
  4454.         return keys;
  4455.       }
  4456.     }
  4457.  
  4458.     return; // parse error
  4459.   }
  4460.  
  4461.   function isIdent(s) {
  4462.     return identRegExp.test(s);
  4463.   }
  4464.  
  4465.   var constructorIsPrivate = {};
  4466.  
  4467.   function Path(parts, privateToken) {
  4468.     if (privateToken !== constructorIsPrivate)
  4469.       throw Error('Use Path.get to retrieve path objects');
  4470.  
  4471.     for (var i = 0; i < parts.length; i++) {
  4472.       this.push(String(parts[i]));
  4473.     }
  4474.  
  4475.     if (hasEval && this.length) {
  4476.       this.getValueFrom = this.compiledGetValueFromFn();
  4477.     }
  4478.   }
  4479.  
  4480.   // TODO(rafaelw): Make simple LRU cache
  4481.   var pathCache = {};
  4482.  
  4483.   function getPath(pathString) {
  4484.     if (pathString instanceof Path)
  4485.       return pathString;
  4486.  
  4487.     if (pathString == null || pathString.length == 0)
  4488.       pathString = '';
  4489.  
  4490.     if (typeof pathString != 'string') {
  4491.       if (isIndex(pathString.length)) {
  4492.         // Constructed with array-like (pre-parsed) keys
  4493.         return new Path(pathString, constructorIsPrivate);
  4494.       }
  4495.  
  4496.       pathString = String(pathString);
  4497.     }
  4498.  
  4499.     var path = pathCache[pathString];
  4500.     if (path)
  4501.       return path;
  4502.  
  4503.     var parts = parsePath(pathString);
  4504.     if (!parts)
  4505.       return invalidPath;
  4506.  
  4507.     var path = new Path(parts, constructorIsPrivate);
  4508.     pathCache[pathString] = path;
  4509.     return path;
  4510.   }
  4511.  
  4512.   Path.get = getPath;
  4513.  
  4514.   function formatAccessor(key) {
  4515.     if (isIndex(key)) {
  4516.       return '[' + key + ']';
  4517.     } else {
  4518.       return '["' + key.replace(/"/g, '\\"') + '"]';
  4519.     }
  4520.   }
  4521.  
  4522.   Path.prototype = createObject({
  4523.     __proto__: [],
  4524.     valid: true,
  4525.  
  4526.     toString: function() {
  4527.       var pathString = '';
  4528.       for (var i = 0; i < this.length; i++) {
  4529.         var key = this[i];
  4530.         if (isIdent(key)) {
  4531.           pathString += i ? '.' + key : key;
  4532.         } else {
  4533.           pathString += formatAccessor(key);
  4534.         }
  4535.       }
  4536.  
  4537.       return pathString;
  4538.     },
  4539.  
  4540.     getValueFrom: function(obj, directObserver) {
  4541.       for (var i = 0; i < this.length; i++) {
  4542.         if (obj == null)
  4543.           return;
  4544.         obj = obj[this[i]];
  4545.       }
  4546.       return obj;
  4547.     },
  4548.  
  4549.     iterateObjects: function(obj, observe) {
  4550.       for (var i = 0; i < this.length; i++) {
  4551.         if (i)
  4552.           obj = obj[this[i - 1]];
  4553.         if (!isObject(obj))
  4554.           return;
  4555.         observe(obj, this[i]);
  4556.       }
  4557.     },
  4558.  
  4559.     compiledGetValueFromFn: function() {
  4560.       var str = '';
  4561.       var pathString = 'obj';
  4562.       str += 'if (obj != null';
  4563.       var i = 0;
  4564.       var key;
  4565.       for (; i < (this.length - 1); i++) {
  4566.         key = this[i];
  4567.         pathString += isIdent(key) ? '.' + key : formatAccessor(key);
  4568.         str += ' &&\n     ' + pathString + ' != null';
  4569.       }
  4570.       str += ')\n';
  4571.  
  4572.       var key = this[i];
  4573.       pathString += isIdent(key) ? '.' + key : formatAccessor(key);
  4574.  
  4575.       str += '  return ' + pathString + ';\nelse\n  return undefined;';
  4576.       return new Function('obj', str);
  4577.     },
  4578.  
  4579.     setValueFrom: function(obj, value) {
  4580.       if (!this.length)
  4581.         return false;
  4582.  
  4583.       for (var i = 0; i < this.length - 1; i++) {
  4584.         if (!isObject(obj))
  4585.           return false;
  4586.         obj = obj[this[i]];
  4587.       }
  4588.  
  4589.       if (!isObject(obj))
  4590.         return false;
  4591.  
  4592.       obj[this[i]] = value;
  4593.       return true;
  4594.     }
  4595.   });
  4596.  
  4597.   var invalidPath = new Path('', constructorIsPrivate);
  4598.   invalidPath.valid = false;
  4599.   invalidPath.getValueFrom = invalidPath.setValueFrom = function() {};
  4600.  
  4601.   var MAX_DIRTY_CHECK_CYCLES = 1000;
  4602.  
  4603.   function dirtyCheck(observer) {
  4604.     var cycles = 0;
  4605.     while (cycles < MAX_DIRTY_CHECK_CYCLES && observer.check_()) {
  4606.       cycles++;
  4607.     }
  4608.     if (testingExposeCycleCount)
  4609.       global.dirtyCheckCycleCount = cycles;
  4610.  
  4611.     return cycles > 0;
  4612.   }
  4613.  
  4614.   function objectIsEmpty(object) {
  4615.     for (var prop in object)
  4616.       return false;
  4617.     return true;
  4618.   }
  4619.  
  4620.   function diffIsEmpty(diff) {
  4621.     return objectIsEmpty(diff.added) &&
  4622.            objectIsEmpty(diff.removed) &&
  4623.            objectIsEmpty(diff.changed);
  4624.   }
  4625.  
  4626.   function diffObjectFromOldObject(object, oldObject) {
  4627.     var added = {};
  4628.     var removed = {};
  4629.     var changed = {};
  4630.  
  4631.     for (var prop in oldObject) {
  4632.       var newValue = object[prop];
  4633.  
  4634.       if (newValue !== undefined && newValue === oldObject[prop])
  4635.         continue;
  4636.  
  4637.       if (!(prop in object)) {
  4638.         removed[prop] = undefined;
  4639.         continue;
  4640.       }
  4641.  
  4642.       if (newValue !== oldObject[prop])
  4643.         changed[prop] = newValue;
  4644.     }
  4645.  
  4646.     for (var prop in object) {
  4647.       if (prop in oldObject)
  4648.         continue;
  4649.  
  4650.       added[prop] = object[prop];
  4651.     }
  4652.  
  4653.     if (Array.isArray(object) && object.length !== oldObject.length)
  4654.       changed.length = object.length;
  4655.  
  4656.     return {
  4657.       added: added,
  4658.       removed: removed,
  4659.       changed: changed
  4660.     };
  4661.   }
  4662.  
  4663.   var eomTasks = [];
  4664.   function runEOMTasks() {
  4665.     if (!eomTasks.length)
  4666.       return false;
  4667.  
  4668.     for (var i = 0; i < eomTasks.length; i++) {
  4669.       eomTasks[i]();
  4670.     }
  4671.     eomTasks.length = 0;
  4672.     return true;
  4673.   }
  4674.  
  4675.   var runEOM = hasObserve ? (function(){
  4676.     return function(fn) {
  4677.       return Promise.resolve().then(fn);
  4678.     }
  4679.   })() :
  4680.   (function() {
  4681.     return function(fn) {
  4682.       eomTasks.push(fn);
  4683.     };
  4684.   })();
  4685.  
  4686.   var observedObjectCache = [];
  4687.  
  4688.   function newObservedObject() {
  4689.     var observer;
  4690.     var object;
  4691.     var discardRecords = false;
  4692.     var first = true;
  4693.  
  4694.     function callback(records) {
  4695.       if (observer && observer.state_ === OPENED && !discardRecords)
  4696.         observer.check_(records);
  4697.     }
  4698.  
  4699.     return {
  4700.       open: function(obs) {
  4701.         if (observer)
  4702.           throw Error('ObservedObject in use');
  4703.  
  4704.         if (!first)
  4705.           Object.deliverChangeRecords(callback);
  4706.  
  4707.         observer = obs;
  4708.         first = false;
  4709.       },
  4710.       observe: function(obj, arrayObserve) {
  4711.         object = obj;
  4712.         if (arrayObserve)
  4713.           Array.observe(object, callback);
  4714.         else
  4715.           Object.observe(object, callback);
  4716.       },
  4717.       deliver: function(discard) {
  4718.         discardRecords = discard;
  4719.         Object.deliverChangeRecords(callback);
  4720.         discardRecords = false;
  4721.       },
  4722.       close: function() {
  4723.         observer = undefined;
  4724.         Object.unobserve(object, callback);
  4725.         observedObjectCache.push(this);
  4726.       }
  4727.     };
  4728.   }
  4729.  
  4730.   /*
  4731.    * The observedSet abstraction is a perf optimization which reduces the total
  4732.    * number of Object.observe observations of a set of objects. The idea is that
  4733.    * groups of Observers will have some object dependencies in common and this
  4734.    * observed set ensures that each object in the transitive closure of
  4735.    * dependencies is only observed once. The observedSet acts as a write barrier
  4736.    * such that whenever any change comes through, all Observers are checked for
  4737.    * changed values.
  4738.    *
  4739.    * Note that this optimization is explicitly moving work from setup-time to
  4740.    * change-time.
  4741.    *
  4742.    * TODO(rafaelw): Implement "garbage collection". In order to move work off
  4743.    * the critical path, when Observers are closed, their observed objects are
  4744.    * not Object.unobserve(d). As a result, it's possible that if the observedSet
  4745.    * is kept open, but some Observers have been closed, it could cause "leaks"
  4746.    * (prevent otherwise collectable objects from being collected). At some
  4747.    * point, we should implement incremental "gc" which keeps a list of
  4748.    * observedSets which may need clean-up and does small amounts of cleanup on a
  4749.    * timeout until all is clean.
  4750.    */
  4751.  
  4752.   function getObservedObject(observer, object, arrayObserve) {
  4753.     var dir = observedObjectCache.pop() || newObservedObject();
  4754.     dir.open(observer);
  4755.     dir.observe(object, arrayObserve);
  4756.     return dir;
  4757.   }
  4758.  
  4759.   var observedSetCache = [];
  4760.  
  4761.   function newObservedSet() {
  4762.     var observerCount = 0;
  4763.     var observers = [];
  4764.     var objects = [];
  4765.     var rootObj;
  4766.     var rootObjProps;
  4767.  
  4768.     function observe(obj, prop) {
  4769.       if (!obj)
  4770.         return;
  4771.  
  4772.       if (obj === rootObj)
  4773.         rootObjProps[prop] = true;
  4774.  
  4775.       if (objects.indexOf(obj) < 0) {
  4776.         objects.push(obj);
  4777.         Object.observe(obj, callback);
  4778.       }
  4779.  
  4780.       observe(Object.getPrototypeOf(obj), prop);
  4781.     }
  4782.  
  4783.     function allRootObjNonObservedProps(recs) {
  4784.       for (var i = 0; i < recs.length; i++) {
  4785.         var rec = recs[i];
  4786.         if (rec.object !== rootObj ||
  4787.             rootObjProps[rec.name] ||
  4788.             rec.type === 'setPrototype') {
  4789.           return false;
  4790.         }
  4791.       }
  4792.       return true;
  4793.     }
  4794.  
  4795.     function callback(recs) {
  4796.       if (allRootObjNonObservedProps(recs))
  4797.         return;
  4798.  
  4799.       var observer;
  4800.       for (var i = 0; i < observers.length; i++) {
  4801.         observer = observers[i];
  4802.         if (observer.state_ == OPENED) {
  4803.           observer.iterateObjects_(observe);
  4804.         }
  4805.       }
  4806.  
  4807.       for (var i = 0; i < observers.length; i++) {
  4808.         observer = observers[i];
  4809.         if (observer.state_ == OPENED) {
  4810.           observer.check_();
  4811.         }
  4812.       }
  4813.     }
  4814.  
  4815.     var record = {
  4816.       objects: objects,
  4817.       get rootObject() { return rootObj; },
  4818.       set rootObject(value) {
  4819.         rootObj = value;
  4820.         rootObjProps = {};
  4821.       },
  4822.       open: function(obs, object) {
  4823.         observers.push(obs);
  4824.         observerCount++;
  4825.         obs.iterateObjects_(observe);
  4826.       },
  4827.       close: function(obs) {
  4828.         observerCount--;
  4829.         if (observerCount > 0) {
  4830.           return;
  4831.         }
  4832.  
  4833.         for (var i = 0; i < objects.length; i++) {
  4834.           Object.unobserve(objects[i], callback);
  4835.           Observer.unobservedCount++;
  4836.         }
  4837.  
  4838.         observers.length = 0;
  4839.         objects.length = 0;
  4840.         rootObj = undefined;
  4841.         rootObjProps = undefined;
  4842.         observedSetCache.push(this);
  4843.         if (lastObservedSet === this)
  4844.           lastObservedSet = null;
  4845.       },
  4846.     };
  4847.  
  4848.     return record;
  4849.   }
  4850.  
  4851.   var lastObservedSet;
  4852.  
  4853.   function getObservedSet(observer, obj) {
  4854.     if (!lastObservedSet || lastObservedSet.rootObject !== obj) {
  4855.       lastObservedSet = observedSetCache.pop() || newObservedSet();
  4856.       lastObservedSet.rootObject = obj;
  4857.     }
  4858.     lastObservedSet.open(observer, obj);
  4859.     return lastObservedSet;
  4860.   }
  4861.  
  4862.   var UNOPENED = 0;
  4863.   var OPENED = 1;
  4864.   var CLOSED = 2;
  4865.   var RESETTING = 3;
  4866.  
  4867.   var nextObserverId = 1;
  4868.  
  4869.   function Observer() {
  4870.     this.state_ = UNOPENED;
  4871.     this.callback_ = undefined;
  4872.     this.target_ = undefined; // TODO(rafaelw): Should be WeakRef
  4873.     this.directObserver_ = undefined;
  4874.     this.value_ = undefined;
  4875.     this.id_ = nextObserverId++;
  4876.   }
  4877.  
  4878.   Observer.prototype = {
  4879.     open: function(callback, target) {
  4880.       if (this.state_ != UNOPENED)
  4881.         throw Error('Observer has already been opened.');
  4882.  
  4883.       addToAll(this);
  4884.       this.callback_ = callback;
  4885.       this.target_ = target;
  4886.       this.connect_();
  4887.       this.state_ = OPENED;
  4888.       return this.value_;
  4889.     },
  4890.  
  4891.     close: function() {
  4892.       if (this.state_ != OPENED)
  4893.         return;
  4894.  
  4895.       removeFromAll(this);
  4896.       this.disconnect_();
  4897.       this.value_ = undefined;
  4898.       this.callback_ = undefined;
  4899.       this.target_ = undefined;
  4900.       this.state_ = CLOSED;
  4901.     },
  4902.  
  4903.     deliver: function() {
  4904.       if (this.state_ != OPENED)
  4905.         return;
  4906.  
  4907.       dirtyCheck(this);
  4908.     },
  4909.  
  4910.     report_: function(changes) {
  4911.       try {
  4912.         this.callback_.apply(this.target_, changes);
  4913.       } catch (ex) {
  4914.         Observer._errorThrownDuringCallback = true;
  4915.         console.error('Exception caught during observer callback: ' +
  4916.                        (ex.stack || ex));
  4917.       }
  4918.     },
  4919.  
  4920.     discardChanges: function() {
  4921.       this.check_(undefined, true);
  4922.       return this.value_;
  4923.     }
  4924.   }
  4925.  
  4926.   var collectObservers = !hasObserve;
  4927.   var allObservers;
  4928.   Observer._allObserversCount = 0;
  4929.  
  4930.   if (collectObservers) {
  4931.     allObservers = [];
  4932.   }
  4933.  
  4934.   function addToAll(observer) {
  4935.     Observer._allObserversCount++;
  4936.     if (!collectObservers)
  4937.       return;
  4938.  
  4939.     allObservers.push(observer);
  4940.   }
  4941.  
  4942.   function removeFromAll(observer) {
  4943.     Observer._allObserversCount--;
  4944.   }
  4945.  
  4946.   var runningMicrotaskCheckpoint = false;
  4947.  
  4948.   global.Platform = global.Platform || {};
  4949.  
  4950.   global.Platform.performMicrotaskCheckpoint = function() {
  4951.     if (runningMicrotaskCheckpoint)
  4952.       return;
  4953.  
  4954.     if (!collectObservers)
  4955.       return;
  4956.  
  4957.     runningMicrotaskCheckpoint = true;
  4958.  
  4959.     var cycles = 0;
  4960.     var anyChanged, toCheck;
  4961.  
  4962.     do {
  4963.       cycles++;
  4964.       toCheck = allObservers;
  4965.       allObservers = [];
  4966.       anyChanged = false;
  4967.  
  4968.       for (var i = 0; i < toCheck.length; i++) {
  4969.         var observer = toCheck[i];
  4970.         if (observer.state_ != OPENED)
  4971.           continue;
  4972.  
  4973.         if (observer.check_())
  4974.           anyChanged = true;
  4975.  
  4976.         allObservers.push(observer);
  4977.       }
  4978.       if (runEOMTasks())
  4979.         anyChanged = true;
  4980.     } while (cycles < MAX_DIRTY_CHECK_CYCLES && anyChanged);
  4981.  
  4982.     if (testingExposeCycleCount)
  4983.       global.dirtyCheckCycleCount = cycles;
  4984.  
  4985.     runningMicrotaskCheckpoint = false;
  4986.   };
  4987.  
  4988.   if (collectObservers) {
  4989.     global.Platform.clearObservers = function() {
  4990.       allObservers = [];
  4991.     };
  4992.   }
  4993.  
  4994.   function ObjectObserver(object) {
  4995.     Observer.call(this);
  4996.     this.value_ = object;
  4997.     this.oldObject_ = undefined;
  4998.   }
  4999.  
  5000.   ObjectObserver.prototype = createObject({
  5001.     __proto__: Observer.prototype,
  5002.  
  5003.     arrayObserve: false,
  5004.  
  5005.     connect_: function(callback, target) {
  5006.       if (hasObserve) {
  5007.         this.directObserver_ = getObservedObject(this, this.value_,
  5008.                                                  this.arrayObserve);
  5009.       } else {
  5010.         this.oldObject_ = this.copyObject(this.value_);
  5011.       }
  5012.  
  5013.     },
  5014.  
  5015.     copyObject: function(object) {
  5016.       var copy = Array.isArray(object) ? [] : {};
  5017.       for (var prop in object) {
  5018.         copy[prop] = object[prop];
  5019.       };
  5020.       if (Array.isArray(object))
  5021.         copy.length = object.length;
  5022.       return copy;
  5023.     },
  5024.  
  5025.     check_: function(changeRecords, skipChanges) {
  5026.       var diff;
  5027.       var oldValues;
  5028.       if (hasObserve) {
  5029.         if (!changeRecords)
  5030.           return false;
  5031.  
  5032.         oldValues = {};
  5033.         diff = diffObjectFromChangeRecords(this.value_, changeRecords,
  5034.                                            oldValues);
  5035.       } else {
  5036.         oldValues = this.oldObject_;
  5037.         diff = diffObjectFromOldObject(this.value_, this.oldObject_);
  5038.       }
  5039.  
  5040.       if (diffIsEmpty(diff))
  5041.         return false;
  5042.  
  5043.       if (!hasObserve)
  5044.         this.oldObject_ = this.copyObject(this.value_);
  5045.  
  5046.       this.report_([
  5047.         diff.added || {},
  5048.         diff.removed || {},
  5049.         diff.changed || {},
  5050.         function(property) {
  5051.           return oldValues[property];
  5052.         }
  5053.       ]);
  5054.  
  5055.       return true;
  5056.     },
  5057.  
  5058.     disconnect_: function() {
  5059.       if (hasObserve) {
  5060.         this.directObserver_.close();
  5061.         this.directObserver_ = undefined;
  5062.       } else {
  5063.         this.oldObject_ = undefined;
  5064.       }
  5065.     },
  5066.  
  5067.     deliver: function() {
  5068.       if (this.state_ != OPENED)
  5069.         return;
  5070.  
  5071.       if (hasObserve)
  5072.         this.directObserver_.deliver(false);
  5073.       else
  5074.         dirtyCheck(this);
  5075.     },
  5076.  
  5077.     discardChanges: function() {
  5078.       if (this.directObserver_)
  5079.         this.directObserver_.deliver(true);
  5080.       else
  5081.         this.oldObject_ = this.copyObject(this.value_);
  5082.  
  5083.       return this.value_;
  5084.     }
  5085.   });
  5086.  
  5087.   function ArrayObserver(array) {
  5088.     if (!Array.isArray(array))
  5089.       throw Error('Provided object is not an Array');
  5090.     ObjectObserver.call(this, array);
  5091.   }
  5092.  
  5093.   ArrayObserver.prototype = createObject({
  5094.  
  5095.     __proto__: ObjectObserver.prototype,
  5096.  
  5097.     arrayObserve: true,
  5098.  
  5099.     copyObject: function(arr) {
  5100.       return arr.slice();
  5101.     },
  5102.  
  5103.     check_: function(changeRecords) {
  5104.       var splices;
  5105.       if (hasObserve) {
  5106.         if (!changeRecords)
  5107.           return false;
  5108.         splices = projectArraySplices(this.value_, changeRecords);
  5109.       } else {
  5110.         splices = calcSplices(this.value_, 0, this.value_.length,
  5111.                               this.oldObject_, 0, this.oldObject_.length);
  5112.       }
  5113.  
  5114.       if (!splices || !splices.length)
  5115.         return false;
  5116.  
  5117.       if (!hasObserve)
  5118.         this.oldObject_ = this.copyObject(this.value_);
  5119.  
  5120.       this.report_([splices]);
  5121.       return true;
  5122.     }
  5123.   });
  5124.  
  5125.   ArrayObserver.applySplices = function(previous, current, splices) {
  5126.     splices.forEach(function(splice) {
  5127.       var spliceArgs = [splice.index, splice.removed.length];
  5128.       var addIndex = splice.index;
  5129.       while (addIndex < splice.index + splice.addedCount) {
  5130.         spliceArgs.push(current[addIndex]);
  5131.         addIndex++;
  5132.       }
  5133.  
  5134.       Array.prototype.splice.apply(previous, spliceArgs);
  5135.     });
  5136.   };
  5137.  
  5138.   function PathObserver(object, path) {
  5139.     Observer.call(this);
  5140.  
  5141.     this.object_ = object;
  5142.     this.path_ = getPath(path);
  5143.     this.directObserver_ = undefined;
  5144.   }
  5145.  
  5146.   PathObserver.prototype = createObject({
  5147.     __proto__: Observer.prototype,
  5148.  
  5149.     get path() {
  5150.       return this.path_;
  5151.     },
  5152.  
  5153.     connect_: function() {
  5154.       if (hasObserve)
  5155.         this.directObserver_ = getObservedSet(this, this.object_);
  5156.  
  5157.       this.check_(undefined, true);
  5158.     },
  5159.  
  5160.     disconnect_: function() {
  5161.       this.value_ = undefined;
  5162.  
  5163.       if (this.directObserver_) {
  5164.         this.directObserver_.close(this);
  5165.         this.directObserver_ = undefined;
  5166.       }
  5167.     },
  5168.  
  5169.     iterateObjects_: function(observe) {
  5170.       this.path_.iterateObjects(this.object_, observe);
  5171.     },
  5172.  
  5173.     check_: function(changeRecords, skipChanges) {
  5174.       var oldValue = this.value_;
  5175.       this.value_ = this.path_.getValueFrom(this.object_);
  5176.       if (skipChanges || areSameValue(this.value_, oldValue))
  5177.         return false;
  5178.  
  5179.       this.report_([this.value_, oldValue, this]);
  5180.       return true;
  5181.     },
  5182.  
  5183.     setValue: function(newValue) {
  5184.       if (this.path_)
  5185.         this.path_.setValueFrom(this.object_, newValue);
  5186.     }
  5187.   });
  5188.  
  5189.   function CompoundObserver(reportChangesOnOpen) {
  5190.     Observer.call(this);
  5191.  
  5192.     this.reportChangesOnOpen_ = reportChangesOnOpen;
  5193.     this.value_ = [];
  5194.     this.directObserver_ = undefined;
  5195.     this.observed_ = [];
  5196.   }
  5197.  
  5198.   var observerSentinel = {};
  5199.  
  5200.   CompoundObserver.prototype = createObject({
  5201.     __proto__: Observer.prototype,
  5202.  
  5203.     connect_: function() {
  5204.       if (hasObserve) {
  5205.         var object;
  5206.         var needsDirectObserver = false;
  5207.         for (var i = 0; i < this.observed_.length; i += 2) {
  5208.           object = this.observed_[i]
  5209.           if (object !== observerSentinel) {
  5210.             needsDirectObserver = true;
  5211.             break;
  5212.           }
  5213.         }
  5214.  
  5215.         if (needsDirectObserver)
  5216.           this.directObserver_ = getObservedSet(this, object);
  5217.       }
  5218.  
  5219.       this.check_(undefined, !this.reportChangesOnOpen_);
  5220.     },
  5221.  
  5222.     disconnect_: function() {
  5223.       for (var i = 0; i < this.observed_.length; i += 2) {
  5224.         if (this.observed_[i] === observerSentinel)
  5225.           this.observed_[i + 1].close();
  5226.       }
  5227.       this.observed_.length = 0;
  5228.       this.value_.length = 0;
  5229.  
  5230.       if (this.directObserver_) {
  5231.         this.directObserver_.close(this);
  5232.         this.directObserver_ = undefined;
  5233.       }
  5234.     },
  5235.  
  5236.     addPath: function(object, path) {
  5237.       if (this.state_ != UNOPENED && this.state_ != RESETTING)
  5238.         throw Error('Cannot add paths once started.');
  5239.  
  5240.       var path = getPath(path);
  5241.       this.observed_.push(object, path);
  5242.       if (!this.reportChangesOnOpen_)
  5243.         return;
  5244.       var index = this.observed_.length / 2 - 1;
  5245.       this.value_[index] = path.getValueFrom(object);
  5246.     },
  5247.  
  5248.     addObserver: function(observer) {
  5249.       if (this.state_ != UNOPENED && this.state_ != RESETTING)
  5250.         throw Error('Cannot add observers once started.');
  5251.  
  5252.       this.observed_.push(observerSentinel, observer);
  5253.       if (!this.reportChangesOnOpen_)
  5254.         return;
  5255.       var index = this.observed_.length / 2 - 1;
  5256.       this.value_[index] = observer.open(this.deliver, this);
  5257.     },
  5258.  
  5259.     startReset: function() {
  5260.       if (this.state_ != OPENED)
  5261.         throw Error('Can only reset while open');
  5262.  
  5263.       this.state_ = RESETTING;
  5264.       this.disconnect_();
  5265.     },
  5266.  
  5267.     finishReset: function() {
  5268.       if (this.state_ != RESETTING)
  5269.         throw Error('Can only finishReset after startReset');
  5270.       this.state_ = OPENED;
  5271.       this.connect_();
  5272.  
  5273.       return this.value_;
  5274.     },
  5275.  
  5276.     iterateObjects_: function(observe) {
  5277.       var object;
  5278.       for (var i = 0; i < this.observed_.length; i += 2) {
  5279.         object = this.observed_[i]
  5280.         if (object !== observerSentinel)
  5281.           this.observed_[i + 1].iterateObjects(object, observe)
  5282.       }
  5283.     },
  5284.  
  5285.     check_: function(changeRecords, skipChanges) {
  5286.       var oldValues;
  5287.       for (var i = 0; i < this.observed_.length; i += 2) {
  5288.         var object = this.observed_[i];
  5289.         var path = this.observed_[i+1];
  5290.         var value;
  5291.         if (object === observerSentinel) {
  5292.           var observable = path;
  5293.           value = this.state_ === UNOPENED ?
  5294.               observable.open(this.deliver, this) :
  5295.               observable.discardChanges();
  5296.         } else {
  5297.           value = path.getValueFrom(object);
  5298.         }
  5299.  
  5300.         if (skipChanges) {
  5301.           this.value_[i / 2] = value;
  5302.           continue;
  5303.         }
  5304.  
  5305.         if (areSameValue(value, this.value_[i / 2]))
  5306.           continue;
  5307.  
  5308.         oldValues = oldValues || [];
  5309.         oldValues[i / 2] = this.value_[i / 2];
  5310.         this.value_[i / 2] = value;
  5311.       }
  5312.  
  5313.       if (!oldValues)
  5314.         return false;
  5315.  
  5316.       // TODO(rafaelw): Having observed_ as the third callback arg here is
  5317.       // pretty lame API. Fix.
  5318.       this.report_([this.value_, oldValues, this.observed_]);
  5319.       return true;
  5320.     }
  5321.   });
  5322.  
  5323.   function identFn(value) { return value; }
  5324.  
  5325.   function ObserverTransform(observable, getValueFn, setValueFn,
  5326.                              dontPassThroughSet) {
  5327.     this.callback_ = undefined;
  5328.     this.target_ = undefined;
  5329.     this.value_ = undefined;
  5330.     this.observable_ = observable;
  5331.     this.getValueFn_ = getValueFn || identFn;
  5332.     this.setValueFn_ = setValueFn || identFn;
  5333.     // TODO(rafaelw): This is a temporary hack. PolymerExpressions needs this
  5334.     // at the moment because of a bug in it's dependency tracking.
  5335.     this.dontPassThroughSet_ = dontPassThroughSet;
  5336.   }
  5337.  
  5338.   ObserverTransform.prototype = {
  5339.     open: function(callback, target) {
  5340.       this.callback_ = callback;
  5341.       this.target_ = target;
  5342.       this.value_ =
  5343.           this.getValueFn_(this.observable_.open(this.observedCallback_, this));
  5344.       return this.value_;
  5345.     },
  5346.  
  5347.     observedCallback_: function(value) {
  5348.       value = this.getValueFn_(value);
  5349.       if (areSameValue(value, this.value_))
  5350.         return;
  5351.       var oldValue = this.value_;
  5352.       this.value_ = value;
  5353.       this.callback_.call(this.target_, this.value_, oldValue);
  5354.     },
  5355.  
  5356.     discardChanges: function() {
  5357.       this.value_ = this.getValueFn_(this.observable_.discardChanges());
  5358.       return this.value_;
  5359.     },
  5360.  
  5361.     deliver: function() {
  5362.       return this.observable_.deliver();
  5363.     },
  5364.  
  5365.     setValue: function(value) {
  5366.       value = this.setValueFn_(value);
  5367.       if (!this.dontPassThroughSet_ && this.observable_.setValue)
  5368.         return this.observable_.setValue(value);
  5369.     },
  5370.  
  5371.     close: function() {
  5372.       if (this.observable_)
  5373.         this.observable_.close();
  5374.       this.callback_ = undefined;
  5375.       this.target_ = undefined;
  5376.       this.observable_ = undefined;
  5377.       this.value_ = undefined;
  5378.       this.getValueFn_ = undefined;
  5379.       this.setValueFn_ = undefined;
  5380.     }
  5381.   }
  5382.  
  5383.   var expectedRecordTypes = {
  5384.     add: true,
  5385.     update: true,
  5386.     delete: true
  5387.   };
  5388.  
  5389.   function diffObjectFromChangeRecords(object, changeRecords, oldValues) {
  5390.     var added = {};
  5391.     var removed = {};
  5392.  
  5393.     for (var i = 0; i < changeRecords.length; i++) {
  5394.       var record = changeRecords[i];
  5395.       if (!expectedRecordTypes[record.type]) {
  5396.         console.error('Unknown changeRecord type: ' + record.type);
  5397.         console.error(record);
  5398.         continue;
  5399.       }
  5400.  
  5401.       if (!(record.name in oldValues))
  5402.         oldValues[record.name] = record.oldValue;
  5403.  
  5404.       if (record.type == 'update')
  5405.         continue;
  5406.  
  5407.       if (record.type == 'add') {
  5408.         if (record.name in removed)
  5409.           delete removed[record.name];
  5410.         else
  5411.           added[record.name] = true;
  5412.  
  5413.         continue;
  5414.       }
  5415.  
  5416.       // type = 'delete'
  5417.       if (record.name in added) {
  5418.         delete added[record.name];
  5419.         delete oldValues[record.name];
  5420.       } else {
  5421.         removed[record.name] = true;
  5422.       }
  5423.     }
  5424.  
  5425.     for (var prop in added)
  5426.       added[prop] = object[prop];
  5427.  
  5428.     for (var prop in removed)
  5429.       removed[prop] = undefined;
  5430.  
  5431.     var changed = {};
  5432.     for (var prop in oldValues) {
  5433.       if (prop in added || prop in removed)
  5434.         continue;
  5435.  
  5436.       var newValue = object[prop];
  5437.       if (oldValues[prop] !== newValue)
  5438.         changed[prop] = newValue;
  5439.     }
  5440.  
  5441.     return {
  5442.       added: added,
  5443.       removed: removed,
  5444.       changed: changed
  5445.     };
  5446.   }
  5447.  
  5448.   function newSplice(index, removed, addedCount) {
  5449.     return {
  5450.       index: index,
  5451.       removed: removed,
  5452.       addedCount: addedCount
  5453.     };
  5454.   }
  5455.  
  5456.   var EDIT_LEAVE = 0;
  5457.   var EDIT_UPDATE = 1;
  5458.   var EDIT_ADD = 2;
  5459.   var EDIT_DELETE = 3;
  5460.  
  5461.   function ArraySplice() {}
  5462.  
  5463.   ArraySplice.prototype = {
  5464.  
  5465.     // Note: This function is *based* on the computation of the Levenshtein
  5466.     // "edit" distance. The one change is that "updates" are treated as two
  5467.     // edits - not one. With Array splices, an update is really a delete
  5468.     // followed by an add. By retaining this, we optimize for "keeping" the
  5469.     // maximum array items in the original array. For example:
  5470.     //
  5471.     //   'xxxx123' -> '123yyyy'
  5472.     //
  5473.     // With 1-edit updates, the shortest path would be just to update all seven
  5474.     // characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
  5475.     // leaves the substring '123' intact.
  5476.     calcEditDistances: function(current, currentStart, currentEnd,
  5477.                                 old, oldStart, oldEnd) {
  5478.       // "Deletion" columns
  5479.       var rowCount = oldEnd - oldStart + 1;
  5480.       var columnCount = currentEnd - currentStart + 1;
  5481.       var distances = new Array(rowCount);
  5482.  
  5483.       // "Addition" rows. Initialize null column.
  5484.       for (var i = 0; i < rowCount; i++) {
  5485.         distances[i] = new Array(columnCount);
  5486.         distances[i][0] = i;
  5487.       }
  5488.  
  5489.       // Initialize null row
  5490.       for (var j = 0; j < columnCount; j++)
  5491.         distances[0][j] = j;
  5492.  
  5493.       for (var i = 1; i < rowCount; i++) {
  5494.         for (var j = 1; j < columnCount; j++) {
  5495.           if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
  5496.             distances[i][j] = distances[i - 1][j - 1];
  5497.           else {
  5498.             var north = distances[i - 1][j] + 1;
  5499.             var west = distances[i][j - 1] + 1;
  5500.             distances[i][j] = north < west ? north : west;
  5501.           }
  5502.         }
  5503.       }
  5504.  
  5505.       return distances;
  5506.     },
  5507.  
  5508.     // This starts at the final weight, and walks "backward" by finding
  5509.     // the minimum previous weight recursively until the origin of the weight
  5510.     // matrix.
  5511.     spliceOperationsFromEditDistances: function(distances) {
  5512.       var i = distances.length - 1;
  5513.       var j = distances[0].length - 1;
  5514.       var current = distances[i][j];
  5515.       var edits = [];
  5516.       while (i > 0 || j > 0) {
  5517.         if (i == 0) {
  5518.           edits.push(EDIT_ADD);
  5519.           j--;
  5520.           continue;
  5521.         }
  5522.         if (j == 0) {
  5523.           edits.push(EDIT_DELETE);
  5524.           i--;
  5525.           continue;
  5526.         }
  5527.         var northWest = distances[i - 1][j - 1];
  5528.         var west = distances[i - 1][j];
  5529.         var north = distances[i][j - 1];
  5530.  
  5531.         var min;
  5532.         if (west < north)
  5533.           min = west < northWest ? west : northWest;
  5534.         else
  5535.           min = north < northWest ? north : northWest;
  5536.  
  5537.         if (min == northWest) {
  5538.           if (northWest == current) {
  5539.             edits.push(EDIT_LEAVE);
  5540.           } else {
  5541.             edits.push(EDIT_UPDATE);
  5542.             current = northWest;
  5543.           }
  5544.           i--;
  5545.           j--;
  5546.         } else if (min == west) {
  5547.           edits.push(EDIT_DELETE);
  5548.           i--;
  5549.           current = west;
  5550.         } else {
  5551.           edits.push(EDIT_ADD);
  5552.           j--;
  5553.           current = north;
  5554.         }
  5555.       }
  5556.  
  5557.       edits.reverse();
  5558.       return edits;
  5559.     },
  5560.  
  5561.     /**
  5562.      * Splice Projection functions:
  5563.      *
  5564.      * A splice map is a representation of how a previous array of items
  5565.      * was transformed into a new array of items. Conceptually it is a list of
  5566.      * tuples of
  5567.      *
  5568.      *   <index, removed, addedCount>
  5569.      *
  5570.      * which are kept in ascending index order of. The tuple represents that at
  5571.      * the |index|, |removed| sequence of items were removed, and counting forward
  5572.      * from |index|, |addedCount| items were added.
  5573.      */
  5574.  
  5575.     /**
  5576.      * Lacking individual splice mutation information, the minimal set of
  5577.      * splices can be synthesized given the previous state and final state of an
  5578.      * array. The basic approach is to calculate the edit distance matrix and
  5579.      * choose the shortest path through it.
  5580.      *
  5581.      * Complexity: O(l * p)
  5582.      *   l: The length of the current array
  5583.      *   p: The length of the old array
  5584.      */
  5585.     calcSplices: function(current, currentStart, currentEnd,
  5586.                           old, oldStart, oldEnd) {
  5587.       var prefixCount = 0;
  5588.       var suffixCount = 0;
  5589.  
  5590.       var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
  5591.       if (currentStart == 0 && oldStart == 0)
  5592.         prefixCount = this.sharedPrefix(current, old, minLength);
  5593.  
  5594.       if (currentEnd == current.length && oldEnd == old.length)
  5595.         suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);
  5596.  
  5597.       currentStart += prefixCount;
  5598.       oldStart += prefixCount;
  5599.       currentEnd -= suffixCount;
  5600.       oldEnd -= suffixCount;
  5601.  
  5602.       if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)
  5603.         return [];
  5604.  
  5605.       if (currentStart == currentEnd) {
  5606.         var splice = newSplice(currentStart, [], 0);
  5607.         while (oldStart < oldEnd)
  5608.           splice.removed.push(old[oldStart++]);
  5609.  
  5610.         return [ splice ];
  5611.       } else if (oldStart == oldEnd)
  5612.         return [ newSplice(currentStart, [], currentEnd - currentStart) ];
  5613.  
  5614.       var ops = this.spliceOperationsFromEditDistances(
  5615.           this.calcEditDistances(current, currentStart, currentEnd,
  5616.                                  old, oldStart, oldEnd));
  5617.  
  5618.       var splice = undefined;
  5619.       var splices = [];
  5620.       var index = currentStart;
  5621.       var oldIndex = oldStart;
  5622.       for (var i = 0; i < ops.length; i++) {
  5623.         switch(ops[i]) {
  5624.           case EDIT_LEAVE:
  5625.             if (splice) {
  5626.               splices.push(splice);
  5627.               splice = undefined;
  5628.             }
  5629.  
  5630.             index++;
  5631.             oldIndex++;
  5632.             break;
  5633.           case EDIT_UPDATE:
  5634.             if (!splice)
  5635.               splice = newSplice(index, [], 0);
  5636.  
  5637.             splice.addedCount++;
  5638.             index++;
  5639.  
  5640.             splice.removed.push(old[oldIndex]);
  5641.             oldIndex++;
  5642.             break;
  5643.           case EDIT_ADD:
  5644.             if (!splice)
  5645.               splice = newSplice(index, [], 0);
  5646.  
  5647.             splice.addedCount++;
  5648.             index++;
  5649.             break;
  5650.           case EDIT_DELETE:
  5651.             if (!splice)
  5652.               splice = newSplice(index, [], 0);
  5653.  
  5654.             splice.removed.push(old[oldIndex]);
  5655.             oldIndex++;
  5656.             break;
  5657.         }
  5658.       }
  5659.  
  5660.       if (splice) {
  5661.         splices.push(splice);
  5662.       }
  5663.       return splices;
  5664.     },
  5665.  
  5666.     sharedPrefix: function(current, old, searchLength) {
  5667.       for (var i = 0; i < searchLength; i++)
  5668.         if (!this.equals(current[i], old[i]))
  5669.           return i;
  5670.       return searchLength;
  5671.     },
  5672.  
  5673.     sharedSuffix: function(current, old, searchLength) {
  5674.       var index1 = current.length;
  5675.       var index2 = old.length;
  5676.       var count = 0;
  5677.       while (count < searchLength && this.equals(current[--index1], old[--index2]))
  5678.         count++;
  5679.  
  5680.       return count;
  5681.     },
  5682.  
  5683.     calculateSplices: function(current, previous) {
  5684.       return this.calcSplices(current, 0, current.length, previous, 0,
  5685.                               previous.length);
  5686.     },
  5687.  
  5688.     equals: function(currentValue, previousValue) {
  5689.       return currentValue === previousValue;
  5690.     }
  5691.   };
  5692.  
  5693.   var arraySplice = new ArraySplice();
  5694.  
  5695.   function calcSplices(current, currentStart, currentEnd,
  5696.                        old, oldStart, oldEnd) {
  5697.     return arraySplice.calcSplices(current, currentStart, currentEnd,
  5698.                                    old, oldStart, oldEnd);
  5699.   }
  5700.  
  5701.   function intersect(start1, end1, start2, end2) {
  5702.     // Disjoint
  5703.     if (end1 < start2 || end2 < start1)
  5704.       return -1;
  5705.  
  5706.     // Adjacent
  5707.     if (end1 == start2 || end2 == start1)
  5708.       return 0;
  5709.  
  5710.     // Non-zero intersect, span1 first
  5711.     if (start1 < start2) {
  5712.       if (end1 < end2)
  5713.         return end1 - start2; // Overlap
  5714.       else
  5715.         return end2 - start2; // Contained
  5716.     } else {
  5717.       // Non-zero intersect, span2 first
  5718.       if (end2 < end1)
  5719.         return end2 - start1; // Overlap
  5720.       else
  5721.         return end1 - start1; // Contained
  5722.     }
  5723.   }
  5724.  
  5725.   function mergeSplice(splices, index, removed, addedCount) {
  5726.  
  5727.     var splice = newSplice(index, removed, addedCount);
  5728.  
  5729.     var inserted = false;
  5730.     var insertionOffset = 0;
  5731.  
  5732.     for (var i = 0; i < splices.length; i++) {
  5733.       var current = splices[i];
  5734.       current.index += insertionOffset;
  5735.  
  5736.       if (inserted)
  5737.         continue;
  5738.  
  5739.       var intersectCount = intersect(splice.index,
  5740.                                      splice.index + splice.removed.length,
  5741.                                      current.index,
  5742.                                      current.index + current.addedCount);
  5743.  
  5744.       if (intersectCount >= 0) {
  5745.         // Merge the two splices
  5746.  
  5747.         splices.splice(i, 1);
  5748.         i--;
  5749.  
  5750.         insertionOffset -= current.addedCount - current.removed.length;
  5751.  
  5752.         splice.addedCount += current.addedCount - intersectCount;
  5753.         var deleteCount = splice.removed.length +
  5754.                           current.removed.length - intersectCount;
  5755.  
  5756.         if (!splice.addedCount && !deleteCount) {
  5757.           // merged splice is a noop. discard.
  5758.           inserted = true;
  5759.         } else {
  5760.           var removed = current.removed;
  5761.  
  5762.           if (splice.index < current.index) {
  5763.             // some prefix of splice.removed is prepended to current.removed.
  5764.             var prepend = splice.removed.slice(0, current.index - splice.index);
  5765.             Array.prototype.push.apply(prepend, removed);
  5766.             removed = prepend;
  5767.           }
  5768.  
  5769.           if (splice.index + splice.removed.length > current.index + current.addedCount) {
  5770.             // some suffix of splice.removed is appended to current.removed.
  5771.             var append = splice.removed.slice(current.index + current.addedCount - splice.index);
  5772.             Array.prototype.push.apply(removed, append);
  5773.           }
  5774.  
  5775.           splice.removed = removed;
  5776.           if (current.index < splice.index) {
  5777.             splice.index = current.index;
  5778.           }
  5779.         }
  5780.       } else if (splice.index < current.index) {
  5781.         // Insert splice here.
  5782.  
  5783.         inserted = true;
  5784.  
  5785.         splices.splice(i, 0, splice);
  5786.         i++;
  5787.  
  5788.         var offset = splice.addedCount - splice.removed.length
  5789.         current.index += offset;
  5790.         insertionOffset += offset;
  5791.       }
  5792.     }
  5793.  
  5794.     if (!inserted)
  5795.       splices.push(splice);
  5796.   }
  5797.  
  5798.   function createInitialSplices(array, changeRecords) {
  5799.     var splices = [];
  5800.  
  5801.     for (var i = 0; i < changeRecords.length; i++) {
  5802.       var record = changeRecords[i];
  5803.       switch(record.type) {
  5804.         case 'splice':
  5805.           mergeSplice(splices, record.index, record.removed.slice(), record.addedCount);
  5806.           break;
  5807.         case 'add':
  5808.         case 'update':
  5809.         case 'delete':
  5810.           if (!isIndex(record.name))
  5811.             continue;
  5812.           var index = toNumber(record.name);
  5813.           if (index < 0)
  5814.             continue;
  5815.           mergeSplice(splices, index, [record.oldValue], 1);
  5816.           break;
  5817.         default:
  5818.           console.error('Unexpected record type: ' + JSON.stringify(record));
  5819.           break;
  5820.       }
  5821.     }
  5822.  
  5823.     return splices;
  5824.   }
  5825.  
  5826.   function projectArraySplices(array, changeRecords) {
  5827.     var splices = [];
  5828.  
  5829.     createInitialSplices(array, changeRecords).forEach(function(splice) {
  5830.       if (splice.addedCount == 1 && splice.removed.length == 1) {
  5831.         if (splice.removed[0] !== array[splice.index])
  5832.           splices.push(splice);
  5833.  
  5834.         return
  5835.       };
  5836.  
  5837.       splices = splices.concat(calcSplices(array, splice.index, splice.index + splice.addedCount,
  5838.                                            splice.removed, 0, splice.removed.length));
  5839.     });
  5840.  
  5841.     return splices;
  5842.   }
  5843.  
  5844.   // Export the observe-js object for **Node.js**, with
  5845.   // backwards-compatibility for the old `require()` API. If we're in
  5846.   // the browser, export as a global object.
  5847.  
  5848.   var expose = global;
  5849.  
  5850.   if (typeof exports !== 'undefined') {
  5851.     if (typeof module !== 'undefined' && module.exports) {
  5852.       expose = exports = module.exports;
  5853.     }
  5854.     expose = exports;
  5855.   } 
  5856.  
  5857.   expose.Observer = Observer;
  5858.   expose.Observer.runEOM_ = runEOM;
  5859.   expose.Observer.observerSentinel_ = observerSentinel; // for testing.
  5860.   expose.Observer.hasObjectObserve = hasObserve;
  5861.   expose.ArrayObserver = ArrayObserver;
  5862.   expose.ArrayObserver.calculateSplices = function(current, previous) {
  5863.     return arraySplice.calculateSplices(current, previous);
  5864.   };
  5865.  
  5866.   expose.ArraySplice = ArraySplice;
  5867.   expose.ObjectObserver = ObjectObserver;
  5868.   expose.PathObserver = PathObserver;
  5869.   expose.CompoundObserver = CompoundObserver;
  5870.   expose.Path = Path;
  5871.   expose.ObserverTransform = ObserverTransform;
  5872.   
  5873. })(typeof global !== 'undefined' && global && typeof module !== 'undefined' && module ? global : this || window);
  5874.  
  5875. // Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
  5876. // This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
  5877. // The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
  5878. // The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
  5879. // Code distributed by Google as part of the polymer project is also
  5880. // subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
  5881.  
  5882. (function(global) {
  5883.   'use strict';
  5884.  
  5885.   var filter = Array.prototype.filter.call.bind(Array.prototype.filter);
  5886.  
  5887.   function getTreeScope(node) {
  5888.     while (node.parentNode) {
  5889.       node = node.parentNode;
  5890.     }
  5891.  
  5892.     return typeof node.getElementById === 'function' ? node : null;
  5893.   }
  5894.  
  5895.   Node.prototype.bind = function(name, observable) {
  5896.     console.error('Unhandled binding to Node: ', this, name, observable);
  5897.   };
  5898.  
  5899.   Node.prototype.bindFinished = function() {};
  5900.  
  5901.   function updateBindings(node, name, binding) {
  5902.     var bindings = node.bindings_;
  5903.     if (!bindings)
  5904.       bindings = node.bindings_ = {};
  5905.  
  5906.     if (bindings[name])
  5907.       binding[name].close();
  5908.  
  5909.     return bindings[name] = binding;
  5910.   }
  5911.  
  5912.   function returnBinding(node, name, binding) {
  5913.     return binding;
  5914.   }
  5915.  
  5916.   function sanitizeValue(value) {
  5917.     return value == null ? '' : value;
  5918.   }
  5919.  
  5920.   function updateText(node, value) {
  5921.     node.data = sanitizeValue(value);
  5922.   }
  5923.  
  5924.   function textBinding(node) {
  5925.     return function(value) {
  5926.       return updateText(node, value);
  5927.     };
  5928.   }
  5929.  
  5930.   var maybeUpdateBindings = returnBinding;
  5931.  
  5932.   Object.defineProperty(Platform, 'enableBindingsReflection', {
  5933.     get: function() {
  5934.       return maybeUpdateBindings === updateBindings;
  5935.     },
  5936.     set: function(enable) {
  5937.       maybeUpdateBindings = enable ? updateBindings : returnBinding;
  5938.       return enable;
  5939.     },
  5940.     configurable: true
  5941.   });
  5942.  
  5943.   Text.prototype.bind = function(name, value, oneTime) {
  5944.     if (name !== 'textContent')
  5945.       return Node.prototype.bind.call(this, name, value, oneTime);
  5946.  
  5947.     if (oneTime)
  5948.       return updateText(this, value);
  5949.  
  5950.     var observable = value;
  5951.     updateText(this, observable.open(textBinding(this)));
  5952.     return maybeUpdateBindings(this, name, observable);
  5953.   }
  5954.  
  5955.   function updateAttribute(el, name, conditional, value) {
  5956.     if (conditional) {
  5957.       if (value)
  5958.         el.setAttribute(name, '');
  5959.       else
  5960.         el.removeAttribute(name);
  5961.       return;
  5962.     }
  5963.  
  5964.     el.setAttribute(name, sanitizeValue(value));
  5965.   }
  5966.  
  5967.   function attributeBinding(el, name, conditional) {
  5968.     return function(value) {
  5969.       updateAttribute(el, name, conditional, value);
  5970.     };
  5971.   }
  5972.  
  5973.   Element.prototype.bind = function(name, value, oneTime) {
  5974.     var conditional = name[name.length - 1] == '?';
  5975.     if (conditional) {
  5976.       this.removeAttribute(name);
  5977.       name = name.slice(0, -1);
  5978.     }
  5979.  
  5980.     if (oneTime)
  5981.       return updateAttribute(this, name, conditional, value);
  5982.  
  5983.  
  5984.     var observable = value;
  5985.     updateAttribute(this, name, conditional,
  5986.         observable.open(attributeBinding(this, name, conditional)));
  5987.  
  5988.     return maybeUpdateBindings(this, name, observable);
  5989.   };
  5990.  
  5991.   var checkboxEventType;
  5992.   (function() {
  5993.     // Attempt to feature-detect which event (change or click) is fired first
  5994.     // for checkboxes.
  5995.     var div = document.createElement('div');
  5996.     var checkbox = div.appendChild(document.createElement('input'));
  5997.     checkbox.setAttribute('type', 'checkbox');
  5998.     var first;
  5999.     var count = 0;
  6000.     checkbox.addEventListener('click', function(e) {
  6001.       count++;
  6002.       first = first || 'click';
  6003.     });
  6004.     checkbox.addEventListener('change', function() {
  6005.       count++;
  6006.       first = first || 'change';
  6007.     });
  6008.  
  6009.     var event = document.createEvent('MouseEvent');
  6010.     event.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false,
  6011.         false, false, false, 0, null);
  6012.     checkbox.dispatchEvent(event);
  6013.     // WebKit/Blink don't fire the change event if the element is outside the
  6014.     // document, so assume 'change' for that case.
  6015.     checkboxEventType = count == 1 ? 'change' : first;
  6016.   })();
  6017.  
  6018.   function getEventForInputType(element) {
  6019.     switch (element.type) {
  6020.       case 'checkbox':
  6021.         return checkboxEventType;
  6022.       case 'radio':
  6023.       case 'select-multiple':
  6024.       case 'select-one':
  6025.         return 'change';
  6026.       case 'range':
  6027.         if (/Trident|MSIE/.test(navigator.userAgent))
  6028.           return 'change';
  6029.       default:
  6030.         return 'input';
  6031.     }
  6032.   }
  6033.  
  6034.   function updateInput(input, property, value, santizeFn) {
  6035.     input[property] = (santizeFn || sanitizeValue)(value);
  6036.   }
  6037.  
  6038.   function inputBinding(input, property, santizeFn) {
  6039.     return function(value) {
  6040.       return updateInput(input, property, value, santizeFn);
  6041.     }
  6042.   }
  6043.  
  6044.   function noop() {}
  6045.  
  6046.   function bindInputEvent(input, property, observable, postEventFn) {
  6047.     var eventType = getEventForInputType(input);
  6048.  
  6049.     function eventHandler() {
  6050.       observable.setValue(input[property]);
  6051.       observable.discardChanges();
  6052.       (postEventFn || noop)(input);
  6053.       Platform.performMicrotaskCheckpoint();
  6054.     }
  6055.     input.addEventListener(eventType, eventHandler);
  6056.  
  6057.     return {
  6058.       close: function() {
  6059.         input.removeEventListener(eventType, eventHandler);
  6060.         observable.close();
  6061.       },
  6062.  
  6063.       observable_: observable
  6064.     }
  6065.   }
  6066.  
  6067.   function booleanSanitize(value) {
  6068.     return Boolean(value);
  6069.   }
  6070.  
  6071.   // |element| is assumed to be an HTMLInputElement with |type| == 'radio'.
  6072.   // Returns an array containing all radio buttons other than |element| that
  6073.   // have the same |name|, either in the form that |element| belongs to or,
  6074.   // if no form, in the document tree to which |element| belongs.
  6075.   //
  6076.   // This implementation is based upon the HTML spec definition of a
  6077.   // "radio button group":
  6078.   //   http://www.whatwg.org/specs/web-apps/current-work/multipage/number-state.html#radio-button-group
  6079.   //
  6080.   function getAssociatedRadioButtons(element) {
  6081.     if (element.form) {
  6082.       return filter(element.form.elements, function(el) {
  6083.         return el != element &&
  6084.             el.tagName == 'INPUT' &&
  6085.             el.type == 'radio' &&
  6086.             el.name == element.name;
  6087.       });
  6088.     } else {
  6089.       var treeScope = getTreeScope(element);
  6090.       if (!treeScope)
  6091.         return [];
  6092.       var radios = treeScope.querySelectorAll(
  6093.           'input[type="radio"][name="' + element.name + '"]');
  6094.       return filter(radios, function(el) {
  6095.         return el != element && !el.form;
  6096.       });
  6097.     }
  6098.   }
  6099.  
  6100.   function checkedPostEvent(input) {
  6101.     // Only the radio button that is getting checked gets an event. We
  6102.     // therefore find all the associated radio buttons and update their
  6103.     // check binding manually.
  6104.     if (input.tagName === 'INPUT' &&
  6105.         input.type === 'radio') {
  6106.       getAssociatedRadioButtons(input).forEach(function(radio) {
  6107.         var checkedBinding = radio.bindings_.checked;
  6108.         if (checkedBinding) {
  6109.           // Set the value directly to avoid an infinite call stack.
  6110.           checkedBinding.observable_.setValue(false);
  6111.         }
  6112.       });
  6113.     }
  6114.   }
  6115.  
  6116.   HTMLInputElement.prototype.bind = function(name, value, oneTime) {
  6117.     if (name !== 'value' && name !== 'checked')
  6118.       return HTMLElement.prototype.bind.call(this, name, value, oneTime);
  6119.  
  6120.     this.removeAttribute(name);
  6121.     var sanitizeFn = name == 'checked' ? booleanSanitize : sanitizeValue;
  6122.     var postEventFn = name == 'checked' ? checkedPostEvent : noop;
  6123.  
  6124.     if (oneTime)
  6125.       return updateInput(this, name, value, sanitizeFn);
  6126.  
  6127.  
  6128.     var observable = value;
  6129.     var binding = bindInputEvent(this, name, observable, postEventFn);
  6130.     updateInput(this, name,
  6131.                 observable.open(inputBinding(this, name, sanitizeFn)),
  6132.                 sanitizeFn);
  6133.  
  6134.     // Checkboxes may need to update bindings of other checkboxes.
  6135.     return updateBindings(this, name, binding);
  6136.   }
  6137.  
  6138.   HTMLTextAreaElement.prototype.bind = function(name, value, oneTime) {
  6139.     if (name !== 'value')
  6140.       return HTMLElement.prototype.bind.call(this, name, value, oneTime);
  6141.  
  6142.     this.removeAttribute('value');
  6143.  
  6144.     if (oneTime)
  6145.       return updateInput(this, 'value', value);
  6146.  
  6147.     var observable = value;
  6148.     var binding = bindInputEvent(this, 'value', observable);
  6149.     updateInput(this, 'value',
  6150.                 observable.open(inputBinding(this, 'value', sanitizeValue)));
  6151.     return maybeUpdateBindings(this, name, binding);
  6152.   }
  6153.  
  6154.   function updateOption(option, value) {
  6155.     var parentNode = option.parentNode;;
  6156.     var select;
  6157.     var selectBinding;
  6158.     var oldValue;
  6159.     if (parentNode instanceof HTMLSelectElement &&
  6160.         parentNode.bindings_ &&
  6161.         parentNode.bindings_.value) {
  6162.       select = parentNode;
  6163.       selectBinding = select.bindings_.value;
  6164.       oldValue = select.value;
  6165.     }
  6166.  
  6167.     option.value = sanitizeValue(value);
  6168.  
  6169.     if (select && select.value != oldValue) {
  6170.       selectBinding.observable_.setValue(select.value);
  6171.       selectBinding.observable_.discardChanges();
  6172.       Platform.performMicrotaskCheckpoint();
  6173.     }
  6174.   }
  6175.  
  6176.   function optionBinding(option) {
  6177.     return function(value) {
  6178.       updateOption(option, value);
  6179.     }
  6180.   }
  6181.  
  6182.   HTMLOptionElement.prototype.bind = function(name, value, oneTime) {
  6183.     if (name !== 'value')
  6184.       return HTMLElement.prototype.bind.call(this, name, value, oneTime);
  6185.  
  6186.     this.removeAttribute('value');
  6187.  
  6188.     if (oneTime)
  6189.       return updateOption(this, value);
  6190.  
  6191.     var observable = value;
  6192.     var binding = bindInputEvent(this, 'value', observable);
  6193.     updateOption(this, observable.open(optionBinding(this)));
  6194.     return maybeUpdateBindings(this, name, binding);
  6195.   }
  6196.  
  6197.   HTMLSelectElement.prototype.bind = function(name, value, oneTime) {
  6198.     if (name === 'selectedindex')
  6199.       name = 'selectedIndex';
  6200.  
  6201.     if (name !== 'selectedIndex' && name !== 'value')
  6202.       return HTMLElement.prototype.bind.call(this, name, value, oneTime);
  6203.  
  6204.     this.removeAttribute(name);
  6205.  
  6206.     if (oneTime)
  6207.       return updateInput(this, name, value);
  6208.  
  6209.     var observable = value;
  6210.     var binding = bindInputEvent(this, name, observable);
  6211.     updateInput(this, name,
  6212.                 observable.open(inputBinding(this, name)));
  6213.  
  6214.     // Option update events may need to access select bindings.
  6215.     return updateBindings(this, name, binding);
  6216.   }
  6217. })(this);
  6218.  
  6219. // Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
  6220. // This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
  6221. // The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
  6222. // The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
  6223. // Code distributed by Google as part of the polymer project is also
  6224. // subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
  6225.  
  6226. (function(global) {
  6227.   'use strict';
  6228.  
  6229.   function assert(v) {
  6230.     if (!v)
  6231.       throw new Error('Assertion failed');
  6232.   }
  6233.  
  6234.   var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
  6235.  
  6236.   function getFragmentRoot(node) {
  6237.     var p;
  6238.     while (p = node.parentNode) {
  6239.       node = p;
  6240.     }
  6241.  
  6242.     return node;
  6243.   }
  6244.  
  6245.   function searchRefId(node, id) {
  6246.     if (!id)
  6247.       return;
  6248.  
  6249.     var ref;
  6250.     var selector = '#' + id;
  6251.     while (!ref) {
  6252.       node = getFragmentRoot(node);
  6253.  
  6254.       if (node.protoContent_)
  6255.         ref = node.protoContent_.querySelector(selector);
  6256.       else if (node.getElementById)
  6257.         ref = node.getElementById(id);
  6258.  
  6259.       if (ref || !node.templateCreator_)
  6260.         break
  6261.  
  6262.       node = node.templateCreator_;
  6263.     }
  6264.  
  6265.     return ref;
  6266.   }
  6267.  
  6268.   function getInstanceRoot(node) {
  6269.     while (node.parentNode) {
  6270.       node = node.parentNode;
  6271.     }
  6272.     return node.templateCreator_ ? node : null;
  6273.   }
  6274.  
  6275.   var Map;
  6276.   if (global.Map && typeof global.Map.prototype.forEach === 'function') {
  6277.     Map = global.Map;
  6278.   } else {
  6279.     Map = function() {
  6280.       this.keys = [];
  6281.       this.values = [];
  6282.     };
  6283.  
  6284.     Map.prototype = {
  6285.       set: function(key, value) {
  6286.         var index = this.keys.indexOf(key);
  6287.         if (index < 0) {
  6288.           this.keys.push(key);
  6289.           this.values.push(value);
  6290.         } else {
  6291.           this.values[index] = value;
  6292.         }
  6293.       },
  6294.  
  6295.       get: function(key) {
  6296.         var index = this.keys.indexOf(key);
  6297.         if (index < 0)
  6298.           return;
  6299.  
  6300.         return this.values[index];
  6301.       },
  6302.  
  6303.       delete: function(key, value) {
  6304.         var index = this.keys.indexOf(key);
  6305.         if (index < 0)
  6306.           return false;
  6307.  
  6308.         this.keys.splice(index, 1);
  6309.         this.values.splice(index, 1);
  6310.         return true;
  6311.       },
  6312.  
  6313.       forEach: function(f, opt_this) {
  6314.         for (var i = 0; i < this.keys.length; i++)
  6315.           f.call(opt_this || this, this.values[i], this.keys[i], this);
  6316.       }
  6317.     };
  6318.   }
  6319.  
  6320.   // JScript does not have __proto__. We wrap all object literals with
  6321.   // createObject which uses Object.create, Object.defineProperty and
  6322.   // Object.getOwnPropertyDescriptor to create a new object that does the exact
  6323.   // same thing. The main downside to this solution is that we have to extract
  6324.   // all those property descriptors for IE.
  6325.   var createObject = ('__proto__' in {}) ?
  6326.       function(obj) { return obj; } :
  6327.       function(obj) {
  6328.         var proto = obj.__proto__;
  6329.         if (!proto)
  6330.           return obj;
  6331.         var newObject = Object.create(proto);
  6332.         Object.getOwnPropertyNames(obj).forEach(function(name) {
  6333.           Object.defineProperty(newObject, name,
  6334.                                Object.getOwnPropertyDescriptor(obj, name));
  6335.         });
  6336.         return newObject;
  6337.       };
  6338.  
  6339.   // IE does not support have Document.prototype.contains.
  6340.   if (typeof document.contains != 'function') {
  6341.     Document.prototype.contains = function(node) {
  6342.       if (node === this || node.parentNode === this)
  6343.         return true;
  6344.       return this.documentElement.contains(node);
  6345.     }
  6346.   }
  6347.  
  6348.   var BIND = 'bind';
  6349.   var REPEAT = 'repeat';
  6350.   var IF = 'if';
  6351.  
  6352.   var templateAttributeDirectives = {
  6353.     'template': true,
  6354.     'repeat': true,
  6355.     'bind': true,
  6356.     'ref': true
  6357.   };
  6358.  
  6359.   var semanticTemplateElements = {
  6360.     'THEAD': true,
  6361.     'TBODY': true,
  6362.     'TFOOT': true,
  6363.     'TH': true,
  6364.     'TR': true,
  6365.     'TD': true,
  6366.     'COLGROUP': true,
  6367.     'COL': true,
  6368.     'CAPTION': true,
  6369.     'OPTION': true,
  6370.     'OPTGROUP': true
  6371.   };
  6372.  
  6373.   var hasTemplateElement = typeof HTMLTemplateElement !== 'undefined';
  6374.   if (hasTemplateElement) {
  6375.     // TODO(rafaelw): Remove when fix for
  6376.     // https://codereview.chromium.org/164803002/
  6377.     // makes it to Chrome release.
  6378.     (function() {
  6379.       var t = document.createElement('template');
  6380.       var d = t.content.ownerDocument;
  6381.       var html = d.appendChild(d.createElement('html'));
  6382.       var head = html.appendChild(d.createElement('head'));
  6383.       var base = d.createElement('base');
  6384.       base.href = document.baseURI;
  6385.       head.appendChild(base);
  6386.     })();
  6387.   }
  6388.  
  6389.   var allTemplatesSelectors = 'template, ' +
  6390.       Object.keys(semanticTemplateElements).map(function(tagName) {
  6391.         return tagName.toLowerCase() + '[template]';
  6392.       }).join(', ');
  6393.  
  6394.   function isSVGTemplate(el) {
  6395.     return el.tagName == 'template' &&
  6396.            el.namespaceURI == 'http://www.w3.org/2000/svg';
  6397.   }
  6398.  
  6399.   function isHTMLTemplate(el) {
  6400.     return el.tagName == 'TEMPLATE' &&
  6401.            el.namespaceURI == 'http://www.w3.org/1999/xhtml';
  6402.   }
  6403.  
  6404.   function isAttributeTemplate(el) {
  6405.     return Boolean(semanticTemplateElements[el.tagName] &&
  6406.                    el.hasAttribute('template'));
  6407.   }
  6408.  
  6409.   function isTemplate(el) {
  6410.     if (el.isTemplate_ === undefined)
  6411.       el.isTemplate_ = el.tagName == 'TEMPLATE' || isAttributeTemplate(el);
  6412.  
  6413.     return el.isTemplate_;
  6414.   }
  6415.  
  6416.   // FIXME: Observe templates being added/removed from documents
  6417.   // FIXME: Expose imperative API to decorate and observe templates in
  6418.   // "disconnected tress" (e.g. ShadowRoot)
  6419.   document.addEventListener('DOMContentLoaded', function(e) {
  6420.     bootstrapTemplatesRecursivelyFrom(document);
  6421.     // FIXME: Is this needed? Seems like it shouldn't be.
  6422.     Platform.performMicrotaskCheckpoint();
  6423.   }, false);
  6424.  
  6425.   function forAllTemplatesFrom(node, fn) {
  6426.     var subTemplates = node.querySelectorAll(allTemplatesSelectors);
  6427.  
  6428.     if (isTemplate(node))
  6429.       fn(node)
  6430.     forEach(subTemplates, fn);
  6431.   }
  6432.  
  6433.   function bootstrapTemplatesRecursivelyFrom(node) {
  6434.     function bootstrap(template) {
  6435.       if (!HTMLTemplateElement.decorate(template))
  6436.         bootstrapTemplatesRecursivelyFrom(template.content);
  6437.     }
  6438.  
  6439.     forAllTemplatesFrom(node, bootstrap);
  6440.   }
  6441.  
  6442.   if (!hasTemplateElement) {
  6443.     /**
  6444.      * This represents a <template> element.
  6445.      * @constructor
  6446.      * @extends {HTMLElement}
  6447.      */
  6448.     global.HTMLTemplateElement = function() {
  6449.       throw TypeError('Illegal constructor');
  6450.     };
  6451.   }
  6452.  
  6453.   var hasProto = '__proto__' in {};
  6454.  
  6455.   function mixin(to, from) {
  6456.     Object.getOwnPropertyNames(from).forEach(function(name) {
  6457.       Object.defineProperty(to, name,
  6458.                             Object.getOwnPropertyDescriptor(from, name));
  6459.     });
  6460.   }
  6461.  
  6462.   // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner
  6463.   function getOrCreateTemplateContentsOwner(template) {
  6464.     var doc = template.ownerDocument
  6465.     if (!doc.defaultView)
  6466.       return doc;
  6467.     var d = doc.templateContentsOwner_;
  6468.     if (!d) {
  6469.       // TODO(arv): This should either be a Document or HTMLDocument depending
  6470.       // on doc.
  6471.       d = doc.implementation.createHTMLDocument('');
  6472.       while (d.lastChild) {
  6473.         d.removeChild(d.lastChild);
  6474.       }
  6475.       doc.templateContentsOwner_ = d;
  6476.     }
  6477.     return d;
  6478.   }
  6479.  
  6480.   function getTemplateStagingDocument(template) {
  6481.     if (!template.stagingDocument_) {
  6482.       var owner = template.ownerDocument;
  6483.       if (!owner.stagingDocument_) {
  6484.         owner.stagingDocument_ = owner.implementation.createHTMLDocument('');
  6485.         owner.stagingDocument_.isStagingDocument = true;
  6486.         // TODO(rafaelw): Remove when fix for
  6487.         // https://codereview.chromium.org/164803002/
  6488.         // makes it to Chrome release.
  6489.         var base = owner.stagingDocument_.createElement('base');
  6490.         base.href = document.baseURI;
  6491.         owner.stagingDocument_.head.appendChild(base);
  6492.  
  6493.         owner.stagingDocument_.stagingDocument_ = owner.stagingDocument_;
  6494.       }
  6495.  
  6496.       template.stagingDocument_ = owner.stagingDocument_;
  6497.     }
  6498.  
  6499.     return template.stagingDocument_;
  6500.   }
  6501.  
  6502.   // For non-template browsers, the parser will disallow <template> in certain
  6503.   // locations, so we allow "attribute templates" which combine the template
  6504.   // element with the top-level container node of the content, e.g.
  6505.   //
  6506.   //   <tr template repeat="{{ foo }}"" class="bar"><td>Bar</td></tr>
  6507.   //
  6508.   // becomes
  6509.   //
  6510.   //   <template repeat="{{ foo }}">
  6511.   //   + #document-fragment
  6512.   //     + <tr class="bar">
  6513.   //       + <td>Bar</td>
  6514.   //
  6515.   function extractTemplateFromAttributeTemplate(el) {
  6516.     var template = el.ownerDocument.createElement('template');
  6517.     el.parentNode.insertBefore(template, el);
  6518.  
  6519.     var attribs = el.attributes;
  6520.     var count = attribs.length;
  6521.     while (count-- > 0) {
  6522.       var attrib = attribs[count];
  6523.       if (templateAttributeDirectives[attrib.name]) {
  6524.         if (attrib.name !== 'template')
  6525.           template.setAttribute(attrib.name, attrib.value);
  6526.         el.removeAttribute(attrib.name);
  6527.       }
  6528.     }
  6529.  
  6530.     return template;
  6531.   }
  6532.  
  6533.   function extractTemplateFromSVGTemplate(el) {
  6534.     var template = el.ownerDocument.createElement('template');
  6535.     el.parentNode.insertBefore(template, el);
  6536.  
  6537.     var attribs = el.attributes;
  6538.     var count = attribs.length;
  6539.     while (count-- > 0) {
  6540.       var attrib = attribs[count];
  6541.       template.setAttribute(attrib.name, attrib.value);
  6542.       el.removeAttribute(attrib.name);
  6543.     }
  6544.  
  6545.     el.parentNode.removeChild(el);
  6546.     return template;
  6547.   }
  6548.  
  6549.   function liftNonNativeTemplateChildrenIntoContent(template, el, useRoot) {
  6550.     var content = template.content;
  6551.     if (useRoot) {
  6552.       content.appendChild(el);
  6553.       return;
  6554.     }
  6555.  
  6556.     var child;
  6557.     while (child = el.firstChild) {
  6558.       content.appendChild(child);
  6559.     }
  6560.   }
  6561.  
  6562.   var templateObserver;
  6563.   if (typeof MutationObserver == 'function') {
  6564.     templateObserver = new MutationObserver(function(records) {
  6565.       for (var i = 0; i < records.length; i++) {
  6566.         records[i].target.refChanged_();
  6567.       }
  6568.     });
  6569.   }
  6570.  
  6571.   /**
  6572.    * Ensures proper API and content model for template elements.
  6573.    * @param {HTMLTemplateElement} opt_instanceRef The template element which
  6574.    *     |el| template element will return as the value of its ref(), and whose
  6575.    *     content will be used as source when createInstance() is invoked.
  6576.    */
  6577.   HTMLTemplateElement.decorate = function(el, opt_instanceRef) {
  6578.     if (el.templateIsDecorated_)
  6579.       return false;
  6580.  
  6581.     var templateElement = el;
  6582.     templateElement.templateIsDecorated_ = true;
  6583.  
  6584.     var isNativeHTMLTemplate = isHTMLTemplate(templateElement) &&
  6585.                                hasTemplateElement;
  6586.     var bootstrapContents = isNativeHTMLTemplate;
  6587.     var liftContents = !isNativeHTMLTemplate;
  6588.     var liftRoot = false;
  6589.  
  6590.     if (!isNativeHTMLTemplate) {
  6591.       if (isAttributeTemplate(templateElement)) {
  6592.         assert(!opt_instanceRef);
  6593.         templateElement = extractTemplateFromAttributeTemplate(el);
  6594.         templateElement.templateIsDecorated_ = true;
  6595.         isNativeHTMLTemplate = hasTemplateElement;
  6596.         liftRoot = true;
  6597.       } else if (isSVGTemplate(templateElement)) {
  6598.         templateElement = extractTemplateFromSVGTemplate(el);
  6599.         templateElement.templateIsDecorated_ = true;
  6600.         isNativeHTMLTemplate = hasTemplateElement;
  6601.       }
  6602.     }
  6603.  
  6604.     if (!isNativeHTMLTemplate) {
  6605.       fixTemplateElementPrototype(templateElement);
  6606.       var doc = getOrCreateTemplateContentsOwner(templateElement);
  6607.       templateElement.content_ = doc.createDocumentFragment();
  6608.     }
  6609.  
  6610.     if (opt_instanceRef) {
  6611.       // template is contained within an instance, its direct content must be
  6612.       // empty
  6613.       templateElement.instanceRef_ = opt_instanceRef;
  6614.     } else if (liftContents) {
  6615.       liftNonNativeTemplateChildrenIntoContent(templateElement,
  6616.                                                el,
  6617.                                                liftRoot);
  6618.     } else if (bootstrapContents) {
  6619.       bootstrapTemplatesRecursivelyFrom(templateElement.content);
  6620.     }
  6621.  
  6622.     return true;
  6623.   };
  6624.  
  6625.   // TODO(rafaelw): This used to decorate recursively all templates from a given
  6626.   // node. This happens by default on 'DOMContentLoaded', but may be needed
  6627.   // in subtrees not descendent from document (e.g. ShadowRoot).
  6628.   // Review whether this is the right public API.
  6629.   HTMLTemplateElement.bootstrap = bootstrapTemplatesRecursivelyFrom;
  6630.  
  6631.   var htmlElement = global.HTMLUnknownElement || HTMLElement;
  6632.  
  6633.   var contentDescriptor = {
  6634.     get: function() {
  6635.       return this.content_;
  6636.     },
  6637.     enumerable: true,
  6638.     configurable: true
  6639.   };
  6640.  
  6641.   if (!hasTemplateElement) {
  6642.     // Gecko is more picky with the prototype than WebKit. Make sure to use the
  6643.     // same prototype as created in the constructor.
  6644.     HTMLTemplateElement.prototype = Object.create(htmlElement.prototype);
  6645.  
  6646.     Object.defineProperty(HTMLTemplateElement.prototype, 'content',
  6647.                           contentDescriptor);
  6648.   }
  6649.  
  6650.   function fixTemplateElementPrototype(el) {
  6651.     if (hasProto)
  6652.       el.__proto__ = HTMLTemplateElement.prototype;
  6653.     else
  6654.       mixin(el, HTMLTemplateElement.prototype);
  6655.   }
  6656.  
  6657.   function ensureSetModelScheduled(template) {
  6658.     if (!template.setModelFn_) {
  6659.       template.setModelFn_ = function() {
  6660.         template.setModelFnScheduled_ = false;
  6661.         var map = getBindings(template,
  6662.             template.delegate_ && template.delegate_.prepareBinding);
  6663.         processBindings(template, map, template.model_);
  6664.       };
  6665.     }
  6666.  
  6667.     if (!template.setModelFnScheduled_) {
  6668.       template.setModelFnScheduled_ = true;
  6669.       Observer.runEOM_(template.setModelFn_);
  6670.     }
  6671.   }
  6672.  
  6673.   mixin(HTMLTemplateElement.prototype, {
  6674.     bind: function(name, value, oneTime) {
  6675.       if (name != 'ref')
  6676.         return Element.prototype.bind.call(this, name, value, oneTime);
  6677.  
  6678.       var self = this;
  6679.       var ref = oneTime ? value : value.open(function(ref) {
  6680.         self.setAttribute('ref', ref);
  6681.         self.refChanged_();
  6682.       });
  6683.  
  6684.       this.setAttribute('ref', ref);
  6685.       this.refChanged_();
  6686.       if (oneTime)
  6687.         return;
  6688.  
  6689.       if (!this.bindings_) {
  6690.         this.bindings_ = { ref: value };
  6691.       } else {
  6692.         this.bindings_.ref = value;
  6693.       }
  6694.  
  6695.       return value;
  6696.     },
  6697.  
  6698.     processBindingDirectives_: function(directives) {
  6699.       if (this.iterator_)
  6700.         this.iterator_.closeDeps();
  6701.  
  6702.       if (!directives.if && !directives.bind && !directives.repeat) {
  6703.         if (this.iterator_) {
  6704.           this.iterator_.close();
  6705.           this.iterator_ = undefined;
  6706.         }
  6707.  
  6708.         return;
  6709.       }
  6710.  
  6711.       if (!this.iterator_) {
  6712.         this.iterator_ = new TemplateIterator(this);
  6713.       }
  6714.  
  6715.       this.iterator_.updateDependencies(directives, this.model_);
  6716.  
  6717.       if (templateObserver) {
  6718.         templateObserver.observe(this, { attributes: true,
  6719.                                          attributeFilter: ['ref'] });
  6720.       }
  6721.  
  6722.       return this.iterator_;
  6723.     },
  6724.  
  6725.     createInstance: function(model, bindingDelegate, delegate_) {
  6726.       if (bindingDelegate)
  6727.         delegate_ = this.newDelegate_(bindingDelegate);
  6728.       else if (!delegate_)
  6729.         delegate_ = this.delegate_;
  6730.  
  6731.       if (!this.refContent_)
  6732.         this.refContent_ = this.ref_.content;
  6733.       var content = this.refContent_;
  6734.       if (content.firstChild === null)
  6735.         return emptyInstance;
  6736.  
  6737.       var map = getInstanceBindingMap(content, delegate_);
  6738.       var stagingDocument = getTemplateStagingDocument(this);
  6739.       var instance = stagingDocument.createDocumentFragment();
  6740.       instance.templateCreator_ = this;
  6741.       instance.protoContent_ = content;
  6742.       instance.bindings_ = [];
  6743.       instance.terminator_ = null;
  6744.       var instanceRecord = instance.templateInstance_ = {
  6745.         firstNode: null,
  6746.         lastNode: null,
  6747.         model: model
  6748.       };
  6749.  
  6750.       var i = 0;
  6751.       var collectTerminator = false;
  6752.       for (var child = content.firstChild; child; child = child.nextSibling) {
  6753.         // The terminator of the instance is the clone of the last child of the
  6754.         // content. If the last child is an active template, it may produce
  6755.         // instances as a result of production, so simply collecting the last
  6756.         // child of the instance after it has finished producing may be wrong.
  6757.         if (child.nextSibling === null)
  6758.           collectTerminator = true;
  6759.  
  6760.         var clone = cloneAndBindInstance(child, instance, stagingDocument,
  6761.                                          map.children[i++],
  6762.                                          model,
  6763.                                          delegate_,
  6764.                                          instance.bindings_);
  6765.         clone.templateInstance_ = instanceRecord;
  6766.         if (collectTerminator)
  6767.           instance.terminator_ = clone;
  6768.       }
  6769.  
  6770.       instanceRecord.firstNode = instance.firstChild;
  6771.       instanceRecord.lastNode = instance.lastChild;
  6772.       instance.templateCreator_ = undefined;
  6773.       instance.protoContent_ = undefined;
  6774.       return instance;
  6775.     },
  6776.  
  6777.     get model() {
  6778.       return this.model_;
  6779.     },
  6780.  
  6781.     set model(model) {
  6782.       this.model_ = model;
  6783.       ensureSetModelScheduled(this);
  6784.     },
  6785.  
  6786.     get bindingDelegate() {
  6787.       return this.delegate_ && this.delegate_.raw;
  6788.     },
  6789.  
  6790.     refChanged_: function() {
  6791.       if (!this.iterator_ || this.refContent_ === this.ref_.content)
  6792.         return;
  6793.  
  6794.       this.refContent_ = undefined;
  6795.       this.iterator_.valueChanged();
  6796.       this.iterator_.updateIteratedValue(this.iterator_.getUpdatedValue());
  6797.     },
  6798.  
  6799.     clear: function() {
  6800.       this.model_ = undefined;
  6801.       this.delegate_ = undefined;
  6802.       if (this.bindings_ && this.bindings_.ref)
  6803.         this.bindings_.ref.close()
  6804.       this.refContent_ = undefined;
  6805.       if (!this.iterator_)
  6806.         return;
  6807.       this.iterator_.valueChanged();
  6808.       this.iterator_.close()
  6809.       this.iterator_ = undefined;
  6810.     },
  6811.  
  6812.     setDelegate_: function(delegate) {
  6813.       this.delegate_ = delegate;
  6814.       this.bindingMap_ = undefined;
  6815.       if (this.iterator_) {
  6816.         this.iterator_.instancePositionChangedFn_ = undefined;
  6817.         this.iterator_.instanceModelFn_ = undefined;
  6818.       }
  6819.     },
  6820.  
  6821.     newDelegate_: function(bindingDelegate) {
  6822.       if (!bindingDelegate)
  6823.         return;
  6824.  
  6825.       function delegateFn(name) {
  6826.         var fn = bindingDelegate && bindingDelegate[name];
  6827.         if (typeof fn != 'function')
  6828.           return;
  6829.  
  6830.         return function() {
  6831.           return fn.apply(bindingDelegate, arguments);
  6832.         };
  6833.       }
  6834.  
  6835.       return {
  6836.         bindingMaps: {},
  6837.         raw: bindingDelegate,
  6838.         prepareBinding: delegateFn('prepareBinding'),
  6839.         prepareInstanceModel: delegateFn('prepareInstanceModel'),
  6840.         prepareInstancePositionChanged:
  6841.             delegateFn('prepareInstancePositionChanged')
  6842.       };
  6843.     },
  6844.  
  6845.     set bindingDelegate(bindingDelegate) {
  6846.       if (this.delegate_) {
  6847.         throw Error('Template must be cleared before a new bindingDelegate ' +
  6848.                     'can be assigned');
  6849.       }
  6850.  
  6851.       this.setDelegate_(this.newDelegate_(bindingDelegate));
  6852.     },
  6853.  
  6854.     get ref_() {
  6855.       var ref = searchRefId(this, this.getAttribute('ref'));
  6856.       if (!ref)
  6857.         ref = this.instanceRef_;
  6858.  
  6859.       if (!ref)
  6860.         return this;
  6861.  
  6862.       var nextRef = ref.ref_;
  6863.       return nextRef ? nextRef : ref;
  6864.     }
  6865.   });
  6866.  
  6867.   // Returns
  6868.   //   a) undefined if there are no mustaches.
  6869.   //   b) [TEXT, (ONE_TIME?, PATH, DELEGATE_FN, TEXT)+] if there is at least one mustache.
  6870.   function parseMustaches(s, name, node, prepareBindingFn) {
  6871.     if (!s || !s.length)
  6872.       return;
  6873.  
  6874.     var tokens;
  6875.     var length = s.length;
  6876.     var startIndex = 0, lastIndex = 0, endIndex = 0;
  6877.     var onlyOneTime = true;
  6878.     while (lastIndex < length) {
  6879.       var startIndex = s.indexOf('{{', lastIndex);
  6880.       var oneTimeStart = s.indexOf('[[', lastIndex);
  6881.       var oneTime = false;
  6882.       var terminator = '}}';
  6883.  
  6884.       if (oneTimeStart >= 0 &&
  6885.           (startIndex < 0 || oneTimeStart < startIndex)) {
  6886.         startIndex = oneTimeStart;
  6887.         oneTime = true;
  6888.         terminator = ']]';
  6889.       }
  6890.  
  6891.       endIndex = startIndex < 0 ? -1 : s.indexOf(terminator, startIndex + 2);
  6892.  
  6893.       if (endIndex < 0) {
  6894.         if (!tokens)
  6895.           return;
  6896.  
  6897.         tokens.push(s.slice(lastIndex)); // TEXT
  6898.         break;
  6899.       }
  6900.  
  6901.       tokens = tokens || [];
  6902.       tokens.push(s.slice(lastIndex, startIndex)); // TEXT
  6903.       var pathString = s.slice(startIndex + 2, endIndex).trim();
  6904.       tokens.push(oneTime); // ONE_TIME?
  6905.       onlyOneTime = onlyOneTime && oneTime;
  6906.       var delegateFn = prepareBindingFn &&
  6907.                        prepareBindingFn(pathString, name, node);
  6908.       // Don't try to parse the expression if there's a prepareBinding function
  6909.       if (delegateFn == null) {
  6910.         tokens.push(Path.get(pathString)); // PATH
  6911.       } else {
  6912.         tokens.push(null);
  6913.       }
  6914.       tokens.push(delegateFn); // DELEGATE_FN
  6915.       lastIndex = endIndex + 2;
  6916.     }
  6917.  
  6918.     if (lastIndex === length)
  6919.       tokens.push(''); // TEXT
  6920.  
  6921.     tokens.hasOnePath = tokens.length === 5;
  6922.     tokens.isSimplePath = tokens.hasOnePath &&
  6923.                           tokens[0] == '' &&
  6924.                           tokens[4] == '';
  6925.     tokens.onlyOneTime = onlyOneTime;
  6926.  
  6927.     tokens.combinator = function(values) {
  6928.       var newValue = tokens[0];
  6929.  
  6930.       for (var i = 1; i < tokens.length; i += 4) {
  6931.         var value = tokens.hasOnePath ? values : values[(i - 1) / 4];
  6932.         if (value !== undefined)
  6933.           newValue += value;
  6934.         newValue += tokens[i + 3];
  6935.       }
  6936.  
  6937.       return newValue;
  6938.     }
  6939.  
  6940.     return tokens;
  6941.   };
  6942.  
  6943.   function processOneTimeBinding(name, tokens, node, model) {
  6944.     if (tokens.hasOnePath) {
  6945.       var delegateFn = tokens[3];
  6946.       var value = delegateFn ? delegateFn(model, node, true) :
  6947.                                tokens[2].getValueFrom(model);
  6948.       return tokens.isSimplePath ? value : tokens.combinator(value);
  6949.     }
  6950.  
  6951.     var values = [];
  6952.     for (var i = 1; i < tokens.length; i += 4) {
  6953.       var delegateFn = tokens[i + 2];
  6954.       values[(i - 1) / 4] = delegateFn ? delegateFn(model, node) :
  6955.           tokens[i + 1].getValueFrom(model);
  6956.     }
  6957.  
  6958.     return tokens.combinator(values);
  6959.   }
  6960.  
  6961.   function processSinglePathBinding(name, tokens, node, model) {
  6962.     var delegateFn = tokens[3];
  6963.     var observer = delegateFn ? delegateFn(model, node, false) :
  6964.         new PathObserver(model, tokens[2]);
  6965.  
  6966.     return tokens.isSimplePath ? observer :
  6967.         new ObserverTransform(observer, tokens.combinator);
  6968.   }
  6969.  
  6970.   function processBinding(name, tokens, node, model) {
  6971.     if (tokens.onlyOneTime)
  6972.       return processOneTimeBinding(name, tokens, node, model);
  6973.  
  6974.     if (tokens.hasOnePath)
  6975.       return processSinglePathBinding(name, tokens, node, model);
  6976.  
  6977.     var observer = new CompoundObserver();
  6978.  
  6979.     for (var i = 1; i < tokens.length; i += 4) {
  6980.       var oneTime = tokens[i];
  6981.       var delegateFn = tokens[i + 2];
  6982.  
  6983.       if (delegateFn) {
  6984.         var value = delegateFn(model, node, oneTime);
  6985.         if (oneTime)
  6986.           observer.addPath(value)
  6987.         else
  6988.           observer.addObserver(value);
  6989.         continue;
  6990.       }
  6991.  
  6992.       var path = tokens[i + 1];
  6993.       if (oneTime)
  6994.         observer.addPath(path.getValueFrom(model))
  6995.       else
  6996.         observer.addPath(model, path);
  6997.     }
  6998.  
  6999.     return new ObserverTransform(observer, tokens.combinator);
  7000.   }
  7001.  
  7002.   function processBindings(node, bindings, model, instanceBindings) {
  7003.     for (var i = 0; i < bindings.length; i += 2) {
  7004.       var name = bindings[i]
  7005.       var tokens = bindings[i + 1];
  7006.       var value = processBinding(name, tokens, node, model);
  7007.       var binding = node.bind(name, value, tokens.onlyOneTime);
  7008.       if (binding && instanceBindings)
  7009.         instanceBindings.push(binding);
  7010.     }
  7011.  
  7012.     node.bindFinished();
  7013.     if (!bindings.isTemplate)
  7014.       return;
  7015.  
  7016.     node.model_ = model;
  7017.     var iter = node.processBindingDirectives_(bindings);
  7018.     if (instanceBindings && iter)
  7019.       instanceBindings.push(iter);
  7020.   }
  7021.  
  7022.   function parseWithDefault(el, name, prepareBindingFn) {
  7023.     var v = el.getAttribute(name);
  7024.     return parseMustaches(v == '' ? '{{}}' : v, name, el, prepareBindingFn);
  7025.   }
  7026.  
  7027.   function parseAttributeBindings(element, prepareBindingFn) {
  7028.     assert(element);
  7029.  
  7030.     var bindings = [];
  7031.     var ifFound = false;
  7032.     var bindFound = false;
  7033.  
  7034.     for (var i = 0; i < element.attributes.length; i++) {
  7035.       var attr = element.attributes[i];
  7036.       var name = attr.name;
  7037.       var value = attr.value;
  7038.  
  7039.       // Allow bindings expressed in attributes to be prefixed with underbars.
  7040.       // We do this to allow correct semantics for browsers that don't implement
  7041.       // <template> where certain attributes might trigger side-effects -- and
  7042.       // for IE which sanitizes certain attributes, disallowing mustache
  7043.       // replacements in their text.
  7044.       while (name[0] === '_') {
  7045.         name = name.substring(1);
  7046.       }
  7047.  
  7048.       if (isTemplate(element) &&
  7049.           (name === IF || name === BIND || name === REPEAT)) {
  7050.         continue;
  7051.       }
  7052.  
  7053.       var tokens = parseMustaches(value, name, element,
  7054.                                   prepareBindingFn);
  7055.       if (!tokens)
  7056.         continue;
  7057.  
  7058.       bindings.push(name, tokens);
  7059.     }
  7060.  
  7061.     if (isTemplate(element)) {
  7062.       bindings.isTemplate = true;
  7063.       bindings.if = parseWithDefault(element, IF, prepareBindingFn);
  7064.       bindings.bind = parseWithDefault(element, BIND, prepareBindingFn);
  7065.       bindings.repeat = parseWithDefault(element, REPEAT, prepareBindingFn);
  7066.  
  7067.       if (bindings.if && !bindings.bind && !bindings.repeat)
  7068.         bindings.bind = parseMustaches('{{}}', BIND, element, prepareBindingFn);
  7069.     }
  7070.  
  7071.     return bindings;
  7072.   }
  7073.  
  7074.   function getBindings(node, prepareBindingFn) {
  7075.     if (node.nodeType === Node.ELEMENT_NODE)
  7076.       return parseAttributeBindings(node, prepareBindingFn);
  7077.  
  7078.     if (node.nodeType === Node.TEXT_NODE) {
  7079.       var tokens = parseMustaches(node.data, 'textContent', node,
  7080.                                   prepareBindingFn);
  7081.       if (tokens)
  7082.         return ['textContent', tokens];
  7083.     }
  7084.  
  7085.     return [];
  7086.   }
  7087.  
  7088.   function cloneAndBindInstance(node, parent, stagingDocument, bindings, model,
  7089.                                 delegate,
  7090.                                 instanceBindings,
  7091.                                 instanceRecord) {
  7092.     var clone = parent.appendChild(stagingDocument.importNode(node, false));
  7093.  
  7094.     var i = 0;
  7095.     for (var child = node.firstChild; child; child = child.nextSibling) {
  7096.       cloneAndBindInstance(child, clone, stagingDocument,
  7097.                             bindings.children[i++],
  7098.                             model,
  7099.                             delegate,
  7100.                             instanceBindings);
  7101.     }
  7102.  
  7103.     if (bindings.isTemplate) {
  7104.       HTMLTemplateElement.decorate(clone, node);
  7105.       if (delegate)
  7106.         clone.setDelegate_(delegate);
  7107.     }
  7108.  
  7109.     processBindings(clone, bindings, model, instanceBindings);
  7110.     return clone;
  7111.   }
  7112.  
  7113.   function createInstanceBindingMap(node, prepareBindingFn) {
  7114.     var map = getBindings(node, prepareBindingFn);
  7115.     map.children = {};
  7116.     var index = 0;
  7117.     for (var child = node.firstChild; child; child = child.nextSibling) {
  7118.       map.children[index++] = createInstanceBindingMap(child, prepareBindingFn);
  7119.     }
  7120.  
  7121.     return map;
  7122.   }
  7123.  
  7124.   var contentUidCounter = 1;
  7125.  
  7126.   // TODO(rafaelw): Setup a MutationObserver on content which clears the id
  7127.   // so that bindingMaps regenerate when the template.content changes.
  7128.   function getContentUid(content) {
  7129.     var id = content.id_;
  7130.     if (!id)
  7131.       id = content.id_ = contentUidCounter++;
  7132.     return id;
  7133.   }
  7134.  
  7135.   // Each delegate is associated with a set of bindingMaps, one for each
  7136.   // content which may be used by a template. The intent is that each binding
  7137.   // delegate gets the opportunity to prepare the instance (via the prepare*
  7138.   // delegate calls) once across all uses.
  7139.   // TODO(rafaelw): Separate out the parse map from the binding map. In the
  7140.   // current implementation, if two delegates need a binding map for the same
  7141.   // content, the second will have to reparse.
  7142.   function getInstanceBindingMap(content, delegate_) {
  7143.     var contentId = getContentUid(content);
  7144.     if (delegate_) {
  7145.       var map = delegate_.bindingMaps[contentId];
  7146.       if (!map) {
  7147.         map = delegate_.bindingMaps[contentId] =
  7148.             createInstanceBindingMap(content, delegate_.prepareBinding) || [];
  7149.       }
  7150.       return map;
  7151.     }
  7152.  
  7153.     var map = content.bindingMap_;
  7154.     if (!map) {
  7155.       map = content.bindingMap_ =
  7156.           createInstanceBindingMap(content, undefined) || [];
  7157.     }
  7158.     return map;
  7159.   }
  7160.  
  7161.   Object.defineProperty(Node.prototype, 'templateInstance', {
  7162.     get: function() {
  7163.       var instance = this.templateInstance_;
  7164.       return instance ? instance :
  7165.           (this.parentNode ? this.parentNode.templateInstance : undefined);
  7166.     }
  7167.   });
  7168.  
  7169.   var emptyInstance = document.createDocumentFragment();
  7170.   emptyInstance.bindings_ = [];
  7171.   emptyInstance.terminator_ = null;
  7172.  
  7173.   function TemplateIterator(templateElement) {
  7174.     this.closed = false;
  7175.     this.templateElement_ = templateElement;
  7176.     this.instances = [];
  7177.     this.deps = undefined;
  7178.     this.iteratedValue = [];
  7179.     this.presentValue = undefined;
  7180.     this.arrayObserver = undefined;
  7181.   }
  7182.  
  7183.   TemplateIterator.prototype = {
  7184.     closeDeps: function() {
  7185.       var deps = this.deps;
  7186.       if (deps) {
  7187.         if (deps.ifOneTime === false)
  7188.           deps.ifValue.close();
  7189.         if (deps.oneTime === false)
  7190.           deps.value.close();
  7191.       }
  7192.     },
  7193.  
  7194.     updateDependencies: function(directives, model) {
  7195.       this.closeDeps();
  7196.  
  7197.       var deps = this.deps = {};
  7198.       var template = this.templateElement_;
  7199.  
  7200.       var ifValue = true;
  7201.       if (directives.if) {
  7202.         deps.hasIf = true;
  7203.         deps.ifOneTime = directives.if.onlyOneTime;
  7204.         deps.ifValue = processBinding(IF, directives.if, template, model);
  7205.  
  7206.         ifValue = deps.ifValue;
  7207.  
  7208.         // oneTime if & predicate is false. nothing else to do.
  7209.         if (deps.ifOneTime && !ifValue) {
  7210.           this.valueChanged();
  7211.           return;
  7212.         }
  7213.  
  7214.         if (!deps.ifOneTime)
  7215.           ifValue = ifValue.open(this.updateIfValue, this);
  7216.       }
  7217.  
  7218.       if (directives.repeat) {
  7219.         deps.repeat = true;
  7220.         deps.oneTime = directives.repeat.onlyOneTime;
  7221.         deps.value = processBinding(REPEAT, directives.repeat, template, model);
  7222.       } else {
  7223.         deps.repeat = false;
  7224.         deps.oneTime = directives.bind.onlyOneTime;
  7225.         deps.value = processBinding(BIND, directives.bind, template, model);
  7226.       }
  7227.  
  7228.       var value = deps.value;
  7229.       if (!deps.oneTime)
  7230.         value = value.open(this.updateIteratedValue, this);
  7231.  
  7232.       if (!ifValue) {
  7233.         this.valueChanged();
  7234.         return;
  7235.       }
  7236.  
  7237.       this.updateValue(value);
  7238.     },
  7239.  
  7240.     /**
  7241.      * Gets the updated value of the bind/repeat. This can potentially call
  7242.      * user code (if a bindingDelegate is set up) so we try to avoid it if we
  7243.      * already have the value in hand (from Observer.open).
  7244.      */
  7245.     getUpdatedValue: function() {
  7246.       var value = this.deps.value;
  7247.       if (!this.deps.oneTime)
  7248.         value = value.discardChanges();
  7249.       return value;
  7250.     },
  7251.  
  7252.     updateIfValue: function(ifValue) {
  7253.       if (!ifValue) {
  7254.         this.valueChanged();
  7255.         return;
  7256.       }
  7257.  
  7258.       this.updateValue(this.getUpdatedValue());
  7259.     },
  7260.  
  7261.     updateIteratedValue: function(value) {
  7262.       if (this.deps.hasIf) {
  7263.         var ifValue = this.deps.ifValue;
  7264.         if (!this.deps.ifOneTime)
  7265.           ifValue = ifValue.discardChanges();
  7266.         if (!ifValue) {
  7267.           this.valueChanged();
  7268.           return;
  7269.         }
  7270.       }
  7271.  
  7272.       this.updateValue(value);
  7273.     },
  7274.  
  7275.     updateValue: function(value) {
  7276.       if (!this.deps.repeat)
  7277.         value = [value];
  7278.       var observe = this.deps.repeat &&
  7279.                     !this.deps.oneTime &&
  7280.                     Array.isArray(value);
  7281.       this.valueChanged(value, observe);
  7282.     },
  7283.  
  7284.     valueChanged: function(value, observeValue) {
  7285.       if (!Array.isArray(value))
  7286.         value = [];
  7287.  
  7288.       if (value === this.iteratedValue)
  7289.         return;
  7290.  
  7291.       this.unobserve();
  7292.       this.presentValue = value;
  7293.       if (observeValue) {
  7294.         this.arrayObserver = new ArrayObserver(this.presentValue);
  7295.         this.arrayObserver.open(this.handleSplices, this);
  7296.       }
  7297.  
  7298.       this.handleSplices(ArrayObserver.calculateSplices(this.presentValue,
  7299.                                                         this.iteratedValue));
  7300.     },
  7301.  
  7302.     getLastInstanceNode: function(index) {
  7303.       if (index == -1)
  7304.         return this.templateElement_;
  7305.       var instance = this.instances[index];
  7306.       var terminator = instance.terminator_;
  7307.       if (!terminator)
  7308.         return this.getLastInstanceNode(index - 1);
  7309.  
  7310.       if (terminator.nodeType !== Node.ELEMENT_NODE ||
  7311.           this.templateElement_ === terminator) {
  7312.         return terminator;
  7313.       }
  7314.  
  7315.       var subtemplateIterator = terminator.iterator_;
  7316.       if (!subtemplateIterator)
  7317.         return terminator;
  7318.  
  7319.       return subtemplateIterator.getLastTemplateNode();
  7320.     },
  7321.  
  7322.     getLastTemplateNode: function() {
  7323.       return this.getLastInstanceNode(this.instances.length - 1);
  7324.     },
  7325.  
  7326.     insertInstanceAt: function(index, fragment) {
  7327.       var previousInstanceLast = this.getLastInstanceNode(index - 1);
  7328.       var parent = this.templateElement_.parentNode;
  7329.       this.instances.splice(index, 0, fragment);
  7330.  
  7331.       parent.insertBefore(fragment, previousInstanceLast.nextSibling);
  7332.     },
  7333.  
  7334.     extractInstanceAt: function(index) {
  7335.       var previousInstanceLast = this.getLastInstanceNode(index - 1);
  7336.       var lastNode = this.getLastInstanceNode(index);
  7337.       var parent = this.templateElement_.parentNode;
  7338.       var instance = this.instances.splice(index, 1)[0];
  7339.  
  7340.       while (lastNode !== previousInstanceLast) {
  7341.         var node = previousInstanceLast.nextSibling;
  7342.         if (node == lastNode)
  7343.           lastNode = previousInstanceLast;
  7344.  
  7345.         instance.appendChild(parent.removeChild(node));
  7346.       }
  7347.  
  7348.       return instance;
  7349.     },
  7350.  
  7351.     getDelegateFn: function(fn) {
  7352.       fn = fn && fn(this.templateElement_);
  7353.       return typeof fn === 'function' ? fn : null;
  7354.     },
  7355.  
  7356.     handleSplices: function(splices) {
  7357.       if (this.closed || !splices.length)
  7358.         return;
  7359.  
  7360.       var template = this.templateElement_;
  7361.  
  7362.       if (!template.parentNode) {
  7363.         this.close();
  7364.         return;
  7365.       }
  7366.  
  7367.       ArrayObserver.applySplices(this.iteratedValue, this.presentValue,
  7368.                                  splices);
  7369.  
  7370.       var delegate = template.delegate_;
  7371.       if (this.instanceModelFn_ === undefined) {
  7372.         this.instanceModelFn_ =
  7373.             this.getDelegateFn(delegate && delegate.prepareInstanceModel);
  7374.       }
  7375.  
  7376.       if (this.instancePositionChangedFn_ === undefined) {
  7377.         this.instancePositionChangedFn_ =
  7378.             this.getDelegateFn(delegate &&
  7379.                                delegate.prepareInstancePositionChanged);
  7380.       }
  7381.  
  7382.       // Instance Removals
  7383.       var instanceCache = new Map;
  7384.       var removeDelta = 0;
  7385.       for (var i = 0; i < splices.length; i++) {
  7386.         var splice = splices[i];
  7387.         var removed = splice.removed;
  7388.         for (var j = 0; j < removed.length; j++) {
  7389.           var model = removed[j];
  7390.           var instance = this.extractInstanceAt(splice.index + removeDelta);
  7391.           if (instance !== emptyInstance) {
  7392.             instanceCache.set(model, instance);
  7393.           }
  7394.         }
  7395.  
  7396.         removeDelta -= splice.addedCount;
  7397.       }
  7398.  
  7399.       // Instance Insertions
  7400.       for (var i = 0; i < splices.length; i++) {
  7401.         var splice = splices[i];
  7402.         var addIndex = splice.index;
  7403.         for (; addIndex < splice.index + splice.addedCount; addIndex++) {
  7404.           var model = this.iteratedValue[addIndex];
  7405.           var instance = instanceCache.get(model);
  7406.           if (instance) {
  7407.             instanceCache.delete(model);
  7408.           } else {
  7409.             if (this.instanceModelFn_) {
  7410.               model = this.instanceModelFn_(model);
  7411.             }
  7412.  
  7413.             if (model === undefined) {
  7414.               instance = emptyInstance;
  7415.             } else {
  7416.               instance = template.createInstance(model, undefined, delegate);
  7417.             }
  7418.           }
  7419.  
  7420.           this.insertInstanceAt(addIndex, instance);
  7421.         }
  7422.       }
  7423.  
  7424.       instanceCache.forEach(function(instance) {
  7425.         this.closeInstanceBindings(instance);
  7426.       }, this);
  7427.  
  7428.       if (this.instancePositionChangedFn_)
  7429.         this.reportInstancesMoved(splices);
  7430.     },
  7431.  
  7432.     reportInstanceMoved: function(index) {
  7433.       var instance = this.instances[index];
  7434.       if (instance === emptyInstance)
  7435.         return;
  7436.  
  7437.       this.instancePositionChangedFn_(instance.templateInstance_, index);
  7438.     },
  7439.  
  7440.     reportInstancesMoved: function(splices) {
  7441.       var index = 0;
  7442.       var offset = 0;
  7443.       for (var i = 0; i < splices.length; i++) {
  7444.         var splice = splices[i];
  7445.         if (offset != 0) {
  7446.           while (index < splice.index) {
  7447.             this.reportInstanceMoved(index);
  7448.             index++;
  7449.           }
  7450.         } else {
  7451.           index = splice.index;
  7452.         }
  7453.  
  7454.         while (index < splice.index + splice.addedCount) {
  7455.           this.reportInstanceMoved(index);
  7456.           index++;
  7457.         }
  7458.  
  7459.         offset += splice.addedCount - splice.removed.length;
  7460.       }
  7461.  
  7462.       if (offset == 0)
  7463.         return;
  7464.  
  7465.       var length = this.instances.length;
  7466.       while (index < length) {
  7467.         this.reportInstanceMoved(index);
  7468.         index++;
  7469.       }
  7470.     },
  7471.  
  7472.     closeInstanceBindings: function(instance) {
  7473.       var bindings = instance.bindings_;
  7474.       for (var i = 0; i < bindings.length; i++) {
  7475.         bindings[i].close();
  7476.       }
  7477.     },
  7478.  
  7479.     unobserve: function() {
  7480.       if (!this.arrayObserver)
  7481.         return;
  7482.  
  7483.       this.arrayObserver.close();
  7484.       this.arrayObserver = undefined;
  7485.     },
  7486.  
  7487.     close: function() {
  7488.       if (this.closed)
  7489.         return;
  7490.       this.unobserve();
  7491.       for (var i = 0; i < this.instances.length; i++) {
  7492.         this.closeInstanceBindings(this.instances[i]);
  7493.       }
  7494.  
  7495.       this.instances.length = 0;
  7496.       this.closeDeps();
  7497.       this.templateElement_.iterator_ = undefined;
  7498.       this.closed = true;
  7499.     }
  7500.   };
  7501.  
  7502.   // Polyfill-specific API.
  7503.   HTMLTemplateElement.forAllTemplatesFrom_ = forAllTemplatesFrom;
  7504. })(this);
  7505.  
  7506. (function(scope) {
  7507.   'use strict';
  7508.  
  7509.   // feature detect for URL constructor
  7510.   var hasWorkingUrl = false;
  7511.   if (!scope.forceJURL) {
  7512.     try {
  7513.       var u = new URL('b', 'http://a');
  7514.       hasWorkingUrl = u.href === 'http://a/b';
  7515.     } catch(e) {}
  7516.   }
  7517.  
  7518.   if (hasWorkingUrl)
  7519.     return;
  7520.  
  7521.   var relative = Object.create(null);
  7522.   relative['ftp'] = 21;
  7523.   relative['file'] = 0;
  7524.   relative['gopher'] = 70;
  7525.   relative['http'] = 80;
  7526.   relative['https'] = 443;
  7527.   relative['ws'] = 80;
  7528.   relative['wss'] = 443;
  7529.  
  7530.   var relativePathDotMapping = Object.create(null);
  7531.   relativePathDotMapping['%2e'] = '.';
  7532.   relativePathDotMapping['.%2e'] = '..';
  7533.   relativePathDotMapping['%2e.'] = '..';
  7534.   relativePathDotMapping['%2e%2e'] = '..';
  7535.  
  7536.   function isRelativeScheme(scheme) {
  7537.     return relative[scheme] !== undefined;
  7538.   }
  7539.  
  7540.   function invalid() {
  7541.     clear.call(this);
  7542.     this._isInvalid = true;
  7543.   }
  7544.  
  7545.   function IDNAToASCII(h) {
  7546.     if ('' == h) {
  7547.       invalid.call(this)
  7548.     }
  7549.     // XXX
  7550.     return h.toLowerCase()
  7551.   }
  7552.  
  7553.   function percentEscape(c) {
  7554.     var unicode = c.charCodeAt(0);
  7555.     if (unicode > 0x20 &&
  7556.        unicode < 0x7F &&
  7557.        // " # < > ? `
  7558.        [0x22, 0x23, 0x3C, 0x3E, 0x3F, 0x60].indexOf(unicode) == -1
  7559.       ) {
  7560.       return c;
  7561.     }
  7562.     return encodeURIComponent(c);
  7563.   }
  7564.  
  7565.   function percentEscapeQuery(c) {
  7566.     // XXX This actually needs to encode c using encoding and then
  7567.     // convert the bytes one-by-one.
  7568.  
  7569.     var unicode = c.charCodeAt(0);
  7570.     if (unicode > 0x20 &&
  7571.        unicode < 0x7F &&
  7572.        // " # < > ` (do not escape '?')
  7573.        [0x22, 0x23, 0x3C, 0x3E, 0x60].indexOf(unicode) == -1
  7574.       ) {
  7575.       return c;
  7576.     }
  7577.     return encodeURIComponent(c);
  7578.   }
  7579.  
  7580.   var EOF = undefined,
  7581.       ALPHA = /[a-zA-Z]/,
  7582.       ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/;
  7583.  
  7584.   function parse(input, stateOverride, base) {
  7585.     function err(message) {
  7586.       errors.push(message)
  7587.     }
  7588.  
  7589.     var state = stateOverride || 'scheme start',
  7590.         cursor = 0,
  7591.         buffer = '',
  7592.         seenAt = false,
  7593.         seenBracket = false,
  7594.         errors = [];
  7595.  
  7596.     loop: while ((input[cursor - 1] != EOF || cursor == 0) && !this._isInvalid) {
  7597.       var c = input[cursor];
  7598.       switch (state) {
  7599.         case 'scheme start':
  7600.           if (c && ALPHA.test(c)) {
  7601.             buffer += c.toLowerCase(); // ASCII-safe
  7602.             state = 'scheme';
  7603.           } else if (!stateOverride) {
  7604.             buffer = '';
  7605.             state = 'no scheme';
  7606.             continue;
  7607.           } else {
  7608.             err('Invalid scheme.');
  7609.             break loop;
  7610.           }
  7611.           break;
  7612.  
  7613.         case 'scheme':
  7614.           if (c && ALPHANUMERIC.test(c)) {
  7615.             buffer += c.toLowerCase(); // ASCII-safe
  7616.           } else if (':' == c) {
  7617.             this._scheme = buffer;
  7618.             buffer = '';
  7619.             if (stateOverride) {
  7620.               break loop;
  7621.             }
  7622.             if (isRelativeScheme(this._scheme)) {
  7623.               this._isRelative = true;
  7624.             }
  7625.             if ('file' == this._scheme) {
  7626.               state = 'relative';
  7627.             } else if (this._isRelative && base && base._scheme == this._scheme) {
  7628.               state = 'relative or authority';
  7629.             } else if (this._isRelative) {
  7630.               state = 'authority first slash';
  7631.             } else {
  7632.               state = 'scheme data';
  7633.             }
  7634.           } else if (!stateOverride) {
  7635.             buffer = '';
  7636.             cursor = 0;
  7637.             state = 'no scheme';
  7638.             continue;
  7639.           } else if (EOF == c) {
  7640.             break loop;
  7641.           } else {
  7642.             err('Code point not allowed in scheme: ' + c)
  7643.             break loop;
  7644.           }
  7645.           break;
  7646.  
  7647.         case 'scheme data':
  7648.           if ('?' == c) {
  7649.             query = '?';
  7650.             state = 'query';
  7651.           } else if ('#' == c) {
  7652.             this._fragment = '#';
  7653.             state = 'fragment';
  7654.           } else {
  7655.             // XXX error handling
  7656.             if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
  7657.               this._schemeData += percentEscape(c);
  7658.             }
  7659.           }
  7660.           break;
  7661.  
  7662.         case 'no scheme':
  7663.           if (!base || !(isRelativeScheme(base._scheme))) {
  7664.             err('Missing scheme.');
  7665.             invalid.call(this);
  7666.           } else {
  7667.             state = 'relative';
  7668.             continue;
  7669.           }
  7670.           break;
  7671.  
  7672.         case 'relative or authority':
  7673.           if ('/' == c && '/' == input[cursor+1]) {
  7674.             state = 'authority ignore slashes';
  7675.           } else {
  7676.             err('Expected /, got: ' + c);
  7677.             state = 'relative';
  7678.             continue
  7679.           }
  7680.           break;
  7681.  
  7682.         case 'relative':
  7683.           this._isRelative = true;
  7684.           if ('file' != this._scheme)
  7685.             this._scheme = base._scheme;
  7686.           if (EOF == c) {
  7687.             this._host = base._host;
  7688.             this._port = base._port;
  7689.             this._path = base._path.slice();
  7690.             this._query = base._query;
  7691.             break loop;
  7692.           } else if ('/' == c || '\\' == c) {
  7693.             if ('\\' == c)
  7694.               err('\\ is an invalid code point.');
  7695.             state = 'relative slash';
  7696.           } else if ('?' == c) {
  7697.             this._host = base._host;
  7698.             this._port = base._port;
  7699.             this._path = base._path.slice();
  7700.             this._query = '?';
  7701.             state = 'query';
  7702.           } else if ('#' == c) {
  7703.             this._host = base._host;
  7704.             this._port = base._port;
  7705.             this._path = base._path.slice();
  7706.             this._query = base._query;
  7707.             this._fragment = '#';
  7708.             state = 'fragment';
  7709.           } else {
  7710.             var nextC = input[cursor+1]
  7711.             var nextNextC = input[cursor+2]
  7712.             if (
  7713.               'file' != this._scheme || !ALPHA.test(c) ||
  7714.               (nextC != ':' && nextC != '|') ||
  7715.               (EOF != nextNextC && '/' != nextNextC && '\\' != nextNextC && '?' != nextNextC && '#' != nextNextC)) {
  7716.               this._host = base._host;
  7717.               this._port = base._port;
  7718.               this._path = base._path.slice();
  7719.               this._path.pop();
  7720.             }
  7721.             state = 'relative path';
  7722.             continue;
  7723.           }
  7724.           break;
  7725.  
  7726.         case 'relative slash':
  7727.           if ('/' == c || '\\' == c) {
  7728.             if ('\\' == c) {
  7729.               err('\\ is an invalid code point.');
  7730.             }
  7731.             if ('file' == this._scheme) {
  7732.               state = 'file host';
  7733.             } else {
  7734.               state = 'authority ignore slashes';
  7735.             }
  7736.           } else {
  7737.             if ('file' != this._scheme) {
  7738.               this._host = base._host;
  7739.               this._port = base._port;
  7740.             }
  7741.             state = 'relative path';
  7742.             continue;
  7743.           }
  7744.           break;
  7745.  
  7746.         case 'authority first slash':
  7747.           if ('/' == c) {
  7748.             state = 'authority second slash';
  7749.           } else {
  7750.             err("Expected '/', got: " + c);
  7751.             state = 'authority ignore slashes';
  7752.             continue;
  7753.           }
  7754.           break;
  7755.  
  7756.         case 'authority second slash':
  7757.           state = 'authority ignore slashes';
  7758.           if ('/' != c) {
  7759.             err("Expected '/', got: " + c);
  7760.             continue;
  7761.           }
  7762.           break;
  7763.  
  7764.         case 'authority ignore slashes':
  7765.           if ('/' != c && '\\' != c) {
  7766.             state = 'authority';
  7767.             continue;
  7768.           } else {
  7769.             err('Expected authority, got: ' + c);
  7770.           }
  7771.           break;
  7772.  
  7773.         case 'authority':
  7774.           if ('@' == c) {
  7775.             if (seenAt) {
  7776.               err('@ already seen.');
  7777.               buffer += '%40';
  7778.             }
  7779.             seenAt = true;
  7780.             for (var i = 0; i < buffer.length; i++) {
  7781.               var cp = buffer[i];
  7782.               if ('\t' == cp || '\n' == cp || '\r' == cp) {
  7783.                 err('Invalid whitespace in authority.');
  7784.                 continue;
  7785.               }
  7786.               // XXX check URL code points
  7787.               if (':' == cp && null === this._password) {
  7788.                 this._password = '';
  7789.                 continue;
  7790.               }
  7791.               var tempC = percentEscape(cp);
  7792.               (null !== this._password) ? this._password += tempC : this._username += tempC;
  7793.             }
  7794.             buffer = '';
  7795.           } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
  7796.             cursor -= buffer.length;
  7797.             buffer = '';
  7798.             state = 'host';
  7799.             continue;
  7800.           } else {
  7801.             buffer += c;
  7802.           }
  7803.           break;
  7804.  
  7805.         case 'file host':
  7806.           if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
  7807.             if (buffer.length == 2 && ALPHA.test(buffer[0]) && (buffer[1] == ':' || buffer[1] == '|')) {
  7808.               state = 'relative path';
  7809.             } else if (buffer.length == 0) {
  7810.               state = 'relative path start';
  7811.             } else {
  7812.               this._host = IDNAToASCII.call(this, buffer);
  7813.               buffer = '';
  7814.               state = 'relative path start';
  7815.             }
  7816.             continue;
  7817.           } else if ('\t' == c || '\n' == c || '\r' == c) {
  7818.             err('Invalid whitespace in file host.');
  7819.           } else {
  7820.             buffer += c;
  7821.           }
  7822.           break;
  7823.  
  7824.         case 'host':
  7825.         case 'hostname':
  7826.           if (':' == c && !seenBracket) {
  7827.             // XXX host parsing
  7828.             this._host = IDNAToASCII.call(this, buffer);
  7829.             buffer = '';
  7830.             state = 'port';
  7831.             if ('hostname' == stateOverride) {
  7832.               break loop;
  7833.             }
  7834.           } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
  7835.             this._host = IDNAToASCII.call(this, buffer);
  7836.             buffer = '';
  7837.             state = 'relative path start';
  7838.             if (stateOverride) {
  7839.               break loop;
  7840.             }
  7841.             continue;
  7842.           } else if ('\t' != c && '\n' != c && '\r' != c) {
  7843.             if ('[' == c) {
  7844.               seenBracket = true;
  7845.             } else if (']' == c) {
  7846.               seenBracket = false;
  7847.             }
  7848.             buffer += c;
  7849.           } else {
  7850.             err('Invalid code point in host/hostname: ' + c);
  7851.           }
  7852.           break;
  7853.  
  7854.         case 'port':
  7855.           if (/[0-9]/.test(c)) {
  7856.             buffer += c;
  7857.           } else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c || stateOverride) {
  7858.             if ('' != buffer) {
  7859.               var temp = parseInt(buffer, 10);
  7860.               if (temp != relative[this._scheme]) {
  7861.                 this._port = temp + '';
  7862.               }
  7863.               buffer = '';
  7864.             }
  7865.             if (stateOverride) {
  7866.               break loop;
  7867.             }
  7868.             state = 'relative path start';
  7869.             continue;
  7870.           } else if ('\t' == c || '\n' == c || '\r' == c) {
  7871.             err('Invalid code point in port: ' + c);
  7872.           } else {
  7873.             invalid.call(this);
  7874.           }
  7875.           break;
  7876.  
  7877.         case 'relative path start':
  7878.           if ('\\' == c)
  7879.             err("'\\' not allowed in path.");
  7880.           state = 'relative path';
  7881.           if ('/' != c && '\\' != c) {
  7882.             continue;
  7883.           }
  7884.           break;
  7885.  
  7886.         case 'relative path':
  7887.           if (EOF == c || '/' == c || '\\' == c || (!stateOverride && ('?' == c || '#' == c))) {
  7888.             if ('\\' == c) {
  7889.               err('\\ not allowed in relative path.');
  7890.             }
  7891.             var tmp;
  7892.             if (tmp = relativePathDotMapping[buffer.toLowerCase()]) {
  7893.               buffer = tmp;
  7894.             }
  7895.             if ('..' == buffer) {
  7896.               this._path.pop();
  7897.               if ('/' != c && '\\' != c) {
  7898.                 this._path.push('');
  7899.               }
  7900.             } else if ('.' == buffer && '/' != c && '\\' != c) {
  7901.               this._path.push('');
  7902.             } else if ('.' != buffer) {
  7903.               if ('file' == this._scheme && this._path.length == 0 && buffer.length == 2 && ALPHA.test(buffer[0]) && buffer[1] == '|') {
  7904.                 buffer = buffer[0] + ':';
  7905.               }
  7906.               this._path.push(buffer);
  7907.             }
  7908.             buffer = '';
  7909.             if ('?' == c) {
  7910.               this._query = '?';
  7911.               state = 'query';
  7912.             } else if ('#' == c) {
  7913.               this._fragment = '#';
  7914.               state = 'fragment';
  7915.             }
  7916.           } else if ('\t' != c && '\n' != c && '\r' != c) {
  7917.             buffer += percentEscape(c);
  7918.           }
  7919.           break;
  7920.  
  7921.         case 'query':
  7922.           if (!stateOverride && '#' == c) {
  7923.             this._fragment = '#';
  7924.             state = 'fragment';
  7925.           } else if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
  7926.             this._query += percentEscapeQuery(c);
  7927.           }
  7928.           break;
  7929.  
  7930.         case 'fragment':
  7931.           if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
  7932.             this._fragment += c;
  7933.           }
  7934.           break;
  7935.       }
  7936.  
  7937.       cursor++;
  7938.     }
  7939.   }
  7940.  
  7941.   function clear() {
  7942.     this._scheme = '';
  7943.     this._schemeData = '';
  7944.     this._username = '';
  7945.     this._password = null;
  7946.     this._host = '';
  7947.     this._port = '';
  7948.     this._path = [];
  7949.     this._query = '';
  7950.     this._fragment = '';
  7951.     this._isInvalid = false;
  7952.     this._isRelative = false;
  7953.   }
  7954.  
  7955.   // Does not process domain names or IP addresses.
  7956.   // Does not handle encoding for the query parameter.
  7957.   function jURL(url, base /* , encoding */) {
  7958.     if (base !== undefined && !(base instanceof jURL))
  7959.       base = new jURL(String(base));
  7960.  
  7961.     this._url = url;
  7962.     clear.call(this);
  7963.  
  7964.     var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, '');
  7965.     // encoding = encoding || 'utf-8'
  7966.  
  7967.     parse.call(this, input, null, base);
  7968.   }
  7969.  
  7970.   jURL.prototype = {
  7971.     get href() {
  7972.       if (this._isInvalid)
  7973.         return this._url;
  7974.  
  7975.       var authority = '';
  7976.       if ('' != this._username || null != this._password) {
  7977.         authority = this._username +
  7978.             (null != this._password ? ':' + this._password : '') + '@';
  7979.       }
  7980.  
  7981.       return this.protocol +
  7982.           (this._isRelative ? '//' + authority + this.host : '') +
  7983.           this.pathname + this._query + this._fragment;
  7984.     },
  7985.     set href(href) {
  7986.       clear.call(this);
  7987.       parse.call(this, href);
  7988.     },
  7989.  
  7990.     get protocol() {
  7991.       return this._scheme + ':';
  7992.     },
  7993.     set protocol(protocol) {
  7994.       if (this._isInvalid)
  7995.         return;
  7996.       parse.call(this, protocol + ':', 'scheme start');
  7997.     },
  7998.  
  7999.     get host() {
  8000.       return this._isInvalid ? '' : this._port ?
  8001.           this._host + ':' + this._port : this._host;
  8002.     },
  8003.     set host(host) {
  8004.       if (this._isInvalid || !this._isRelative)
  8005.         return;
  8006.       parse.call(this, host, 'host');
  8007.     },
  8008.  
  8009.     get hostname() {
  8010.       return this._host;
  8011.     },
  8012.     set hostname(hostname) {
  8013.       if (this._isInvalid || !this._isRelative)
  8014.         return;
  8015.       parse.call(this, hostname, 'hostname');
  8016.     },
  8017.  
  8018.     get port() {
  8019.       return this._port;
  8020.     },
  8021.     set port(port) {
  8022.       if (this._isInvalid || !this._isRelative)
  8023.         return;
  8024.       parse.call(this, port, 'port');
  8025.     },
  8026.  
  8027.     get pathname() {
  8028.       return this._isInvalid ? '' : this._isRelative ?
  8029.           '/' + this._path.join('/') : this._schemeData;
  8030.     },
  8031.     set pathname(pathname) {
  8032.       if (this._isInvalid || !this._isRelative)
  8033.         return;
  8034.       this._path = [];
  8035.       parse.call(this, pathname, 'relative path start');
  8036.     },
  8037.  
  8038.     get search() {
  8039.       return this._isInvalid || !this._query || '?' == this._query ?
  8040.           '' : this._query;
  8041.     },
  8042.     set search(search) {
  8043.       if (this._isInvalid || !this._isRelative)
  8044.         return;
  8045.       this._query = '?';
  8046.       if ('?' == search[0])
  8047.         search = search.slice(1);
  8048.       parse.call(this, search, 'query');
  8049.     },
  8050.  
  8051.     get hash() {
  8052.       return this._isInvalid || !this._fragment || '#' == this._fragment ?
  8053.           '' : this._fragment;
  8054.     },
  8055.     set hash(hash) {
  8056.       if (this._isInvalid)
  8057.         return;
  8058.       this._fragment = '#';
  8059.       if ('#' == hash[0])
  8060.         hash = hash.slice(1);
  8061.       parse.call(this, hash, 'fragment');
  8062.     },
  8063.  
  8064.     get origin() {
  8065.       var host;
  8066.       if (this._isInvalid || !this._scheme) {
  8067.         return '';
  8068.       }
  8069.       // javascript: Gecko returns String(""), WebKit/Blink String("null")
  8070.       // Gecko throws error for "data://"
  8071.       // data: Gecko returns "", Blink returns "data://", WebKit returns "null"
  8072.       // Gecko returns String("") for file: mailto:
  8073.       // WebKit/Blink returns String("SCHEME://") for file: mailto:
  8074.       switch (this._scheme) {
  8075.         case 'data':
  8076.         case 'file':
  8077.         case 'javascript':
  8078.         case 'mailto':
  8079.           return 'null';
  8080.       }
  8081.       host = this.host;
  8082.       if (!host) {
  8083.         return '';
  8084.       }
  8085.       return this._scheme + '://' + host;
  8086.     }
  8087.   };
  8088.  
  8089.   // Copy over the static methods
  8090.   var OriginalURL = scope.URL;
  8091.   if (OriginalURL) {
  8092.     jURL.createObjectURL = function(blob) {
  8093.       // IE extension allows a second optional options argument.
  8094.       // http://msdn.microsoft.com/en-us/library/ie/hh772302(v=vs.85).aspx
  8095.       return OriginalURL.createObjectURL.apply(OriginalURL, arguments);
  8096.     };
  8097.     jURL.revokeObjectURL = function(url) {
  8098.       OriginalURL.revokeObjectURL(url);
  8099.     };
  8100.   }
  8101.  
  8102.   scope.URL = jURL;
  8103.  
  8104. })(this);
  8105.  
  8106. (function(scope) {
  8107.  
  8108. var iterations = 0;
  8109. var callbacks = [];
  8110. var twiddle = document.createTextNode('');
  8111.  
  8112. function endOfMicrotask(callback) {
  8113.   twiddle.textContent = iterations++;
  8114.   callbacks.push(callback);
  8115. }
  8116.  
  8117. function atEndOfMicrotask() {
  8118.   while (callbacks.length) {
  8119.     callbacks.shift()();
  8120.   }
  8121. }
  8122.  
  8123. new (window.MutationObserver || JsMutationObserver)(atEndOfMicrotask)
  8124.   .observe(twiddle, {characterData: true})
  8125.   ;
  8126.  
  8127. // exports
  8128. scope.endOfMicrotask = endOfMicrotask;
  8129. // bc 
  8130. Platform.endOfMicrotask = endOfMicrotask;
  8131.  
  8132. })(Polymer);
  8133.  
  8134.  
  8135. (function(scope) {
  8136.  
  8137. /**
  8138.  * @class Polymer
  8139.  */
  8140.  
  8141. // imports
  8142. var endOfMicrotask = scope.endOfMicrotask;
  8143.  
  8144. // logging
  8145. var log = window.WebComponents ? WebComponents.flags.log : {};
  8146.  
  8147. // inject style sheet
  8148. var style = document.createElement('style');
  8149. style.textContent = 'template {display: none !important;} /* injected by platform.js */';
  8150. var head = document.querySelector('head');
  8151. head.insertBefore(style, head.firstChild);
  8152.  
  8153.  
  8154. /**
  8155.  * Force any pending data changes to be observed before 
  8156.  * the next task. Data changes are processed asynchronously but are guaranteed
  8157.  * to be processed, for example, before painting. This method should rarely be 
  8158.  * needed. It does nothing when Object.observe is available; 
  8159.  * when Object.observe is not available, Polymer automatically flushes data 
  8160.  * changes approximately every 1/10 second. 
  8161.  * Therefore, `flush` should only be used when a data mutation should be 
  8162.  * observed sooner than this.
  8163.  * 
  8164.  * @method flush
  8165.  */
  8166. // flush (with logging)
  8167. var flushing;
  8168. function flush() {
  8169.   if (!flushing) {
  8170.     flushing = true;
  8171.     endOfMicrotask(function() {
  8172.       flushing = false;
  8173.       log.data && console.group('flush');
  8174.       Platform.performMicrotaskCheckpoint();
  8175.       log.data && console.groupEnd();
  8176.     });
  8177.   }
  8178. };
  8179.  
  8180. // polling dirty checker
  8181. // flush periodically if platform does not have object observe.
  8182. if (!Observer.hasObjectObserve) {
  8183.   var FLUSH_POLL_INTERVAL = 125;
  8184.   window.addEventListener('WebComponentsReady', function() {
  8185.     flush();
  8186.     // watch document visiblity to toggle dirty-checking
  8187.     var visibilityHandler = function() {
  8188.       // only flush if the page is visibile
  8189.       if (document.visibilityState === 'hidden') {
  8190.         if (scope.flushPoll) {
  8191.           clearInterval(scope.flushPoll);
  8192.         }
  8193.       } else {
  8194.         scope.flushPoll = setInterval(flush, FLUSH_POLL_INTERVAL);
  8195.       }
  8196.     };
  8197.     if (typeof document.visibilityState === 'string') {
  8198.       document.addEventListener('visibilitychange', visibilityHandler);
  8199.     }
  8200.     visibilityHandler();
  8201.   });
  8202. } else {
  8203.   // make flush a no-op when we have Object.observe
  8204.   flush = function() {};
  8205. }
  8206.  
  8207. if (window.CustomElements && !CustomElements.useNative) {
  8208.   var originalImportNode = Document.prototype.importNode;
  8209.   Document.prototype.importNode = function(node, deep) {
  8210.     var imported = originalImportNode.call(this, node, deep);
  8211.     CustomElements.upgradeAll(imported);
  8212.     return imported;
  8213.   };
  8214. }
  8215.  
  8216. // exports
  8217. scope.flush = flush;
  8218. // bc
  8219. Platform.flush = flush;
  8220.  
  8221. })(window.Polymer);
  8222.  
  8223.  
  8224. (function(scope) {
  8225.  
  8226. var urlResolver = {
  8227.   resolveDom: function(root, url) {
  8228.     url = url || baseUrl(root);
  8229.     this.resolveAttributes(root, url);
  8230.     this.resolveStyles(root, url);
  8231.     // handle template.content
  8232.     var templates = root.querySelectorAll('template');
  8233.     if (templates) {
  8234.       for (var i = 0, l = templates.length, t; (i < l) && (t = templates[i]); i++) {
  8235.         if (t.content) {
  8236.           this.resolveDom(t.content, url);
  8237.         }
  8238.       }
  8239.     }
  8240.   },
  8241.   resolveTemplate: function(template) {
  8242.     this.resolveDom(template.content, baseUrl(template));
  8243.   },
  8244.   resolveStyles: function(root, url) {
  8245.     var styles = root.querySelectorAll('style');
  8246.     if (styles) {
  8247.       for (var i = 0, l = styles.length, s; (i < l) && (s = styles[i]); i++) {
  8248.         this.resolveStyle(s, url);
  8249.       }
  8250.     }
  8251.   },
  8252.   resolveStyle: function(style, url) {
  8253.     url = url || baseUrl(style);
  8254.     style.textContent = this.resolveCssText(style.textContent, url);
  8255.   },
  8256.   resolveCssText: function(cssText, baseUrl, keepAbsolute) {
  8257.     cssText = replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, CSS_URL_REGEXP);
  8258.     return replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, CSS_IMPORT_REGEXP);
  8259.   },
  8260.   resolveAttributes: function(root, url) {
  8261.     if (root.hasAttributes && root.hasAttributes()) {
  8262.       this.resolveElementAttributes(root, url);
  8263.     }
  8264.     // search for attributes that host urls
  8265.     var nodes = root && root.querySelectorAll(URL_ATTRS_SELECTOR);
  8266.     if (nodes) {
  8267.       for (var i = 0, l = nodes.length, n; (i < l) && (n = nodes[i]); i++) {
  8268.         this.resolveElementAttributes(n, url);
  8269.       }
  8270.     }
  8271.   },
  8272.   resolveElementAttributes: function(node, url) {
  8273.     url = url || baseUrl(node);
  8274.     URL_ATTRS.forEach(function(v) {
  8275.       var attr = node.attributes[v];
  8276.       var value = attr && attr.value;
  8277.       var replacement;
  8278.       if (value && value.search(URL_TEMPLATE_SEARCH) < 0) {
  8279.         if (v === 'style') {
  8280.           replacement = replaceUrlsInCssText(value, url, false, CSS_URL_REGEXP);
  8281.         } else {
  8282.           replacement = resolveRelativeUrl(url, value);
  8283.         }
  8284.         attr.value = replacement;
  8285.       }
  8286.     });
  8287.   }
  8288. };
  8289.  
  8290. var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g;
  8291. var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g;
  8292. var URL_ATTRS = ['href', 'src', 'action', 'style', 'url'];
  8293. var URL_ATTRS_SELECTOR = '[' + URL_ATTRS.join('],[') + ']';
  8294. var URL_TEMPLATE_SEARCH = '{{.*}}';
  8295. var URL_HASH = '#';
  8296.  
  8297. function baseUrl(node) {
  8298.   var u = new URL(node.ownerDocument.baseURI);
  8299.   u.search = '';
  8300.   u.hash = '';
  8301.   return u;
  8302. }
  8303.  
  8304. function replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, regexp) {
  8305.   return cssText.replace(regexp, function(m, pre, url, post) {
  8306.     var urlPath = url.replace(/["']/g, '');
  8307.     urlPath = resolveRelativeUrl(baseUrl, urlPath, keepAbsolute);
  8308.     return pre + '\'' + urlPath + '\'' + post;
  8309.   });
  8310. }
  8311.  
  8312. function resolveRelativeUrl(baseUrl, url, keepAbsolute) {
  8313.   // do not resolve '/' absolute urls
  8314.   if (url && url[0] === '/') {
  8315.     return url;
  8316.   }
  8317.   var u = new URL(url, baseUrl);
  8318.   return keepAbsolute ? u.href : makeDocumentRelPath(u.href);
  8319. }
  8320.  
  8321. function makeDocumentRelPath(url) {
  8322.   var root = baseUrl(document.documentElement);
  8323.   var u = new URL(url, root);
  8324.   if (u.host === root.host && u.port === root.port &&
  8325.       u.protocol === root.protocol) {
  8326.     return makeRelPath(root, u);
  8327.   } else {
  8328.     return url;
  8329.   }
  8330. }
  8331.  
  8332. // make a relative path from source to target
  8333. function makeRelPath(sourceUrl, targetUrl) {
  8334.   var source = sourceUrl.pathname;
  8335.   var target = targetUrl.pathname;
  8336.   var s = source.split('/');
  8337.   var t = target.split('/');
  8338.   while (s.length && s[0] === t[0]){
  8339.     s.shift();
  8340.     t.shift();
  8341.   }
  8342.   for (var i = 0, l = s.length - 1; i < l; i++) {
  8343.     t.unshift('..');
  8344.   }
  8345.   // empty '#' is discarded but we need to preserve it.
  8346.   var hash = (targetUrl.href.slice(-1) === URL_HASH) ? URL_HASH : targetUrl.hash;
  8347.   return t.join('/') + targetUrl.search + hash;
  8348. }
  8349.  
  8350. // exports
  8351. scope.urlResolver = urlResolver;
  8352.  
  8353. })(Polymer);
  8354.  
  8355. (function(scope) {
  8356.   var endOfMicrotask = Polymer.endOfMicrotask;
  8357.  
  8358.   // Generic url loader
  8359.   function Loader(regex) {
  8360.     this.cache = Object.create(null);
  8361.     this.map = Object.create(null);
  8362.     this.requests = 0;
  8363.     this.regex = regex;
  8364.   }
  8365.   Loader.prototype = {
  8366.  
  8367.     // TODO(dfreedm): there may be a better factoring here
  8368.     // extract absolute urls from the text (full of relative urls)
  8369.     extractUrls: function(text, base) {
  8370.       var matches = [];
  8371.       var matched, u;
  8372.       while ((matched = this.regex.exec(text))) {
  8373.         u = new URL(matched[1], base);
  8374.         matches.push({matched: matched[0], url: u.href});
  8375.       }
  8376.       return matches;
  8377.     },
  8378.     // take a text blob, a root url, and a callback and load all the urls found within the text
  8379.     // returns a map of absolute url to text
  8380.     process: function(text, root, callback) {
  8381.       var matches = this.extractUrls(text, root);
  8382.  
  8383.       // every call to process returns all the text this loader has ever received
  8384.       var done = callback.bind(null, this.map);
  8385.       this.fetch(matches, done);
  8386.     },
  8387.     // build a mapping of url -> text from matches
  8388.     fetch: function(matches, callback) {
  8389.       var inflight = matches.length;
  8390.  
  8391.       // return early if there is no fetching to be done
  8392.       if (!inflight) {
  8393.         return callback();
  8394.       }
  8395.  
  8396.       // wait for all subrequests to return
  8397.       var done = function() {
  8398.         if (--inflight === 0) {
  8399.           callback();
  8400.         }
  8401.       };
  8402.  
  8403.       // start fetching all subrequests
  8404.       var m, req, url;
  8405.       for (var i = 0; i < inflight; i++) {
  8406.         m = matches[i];
  8407.         url = m.url;
  8408.         req = this.cache[url];
  8409.         // if this url has already been requested, skip requesting it again
  8410.         if (!req) {
  8411.           req = this.xhr(url);
  8412.           req.match = m;
  8413.           this.cache[url] = req;
  8414.         }
  8415.         // wait for the request to process its subrequests
  8416.         req.wait(done);
  8417.       }
  8418.     },
  8419.     handleXhr: function(request) {
  8420.       var match = request.match;
  8421.       var url = match.url;
  8422.  
  8423.       // handle errors with an empty string
  8424.       var response = request.response || request.responseText || '';
  8425.       this.map[url] = response;
  8426.       this.fetch(this.extractUrls(response, url), request.resolve);
  8427.     },
  8428.     xhr: function(url) {
  8429.       this.requests++;
  8430.       var request = new XMLHttpRequest();
  8431.       request.open('GET', url, true);
  8432.       request.send();
  8433.       request.onerror = request.onload = this.handleXhr.bind(this, request);
  8434.  
  8435.       // queue of tasks to run after XHR returns
  8436.       request.pending = [];
  8437.       request.resolve = function() {
  8438.         var pending = request.pending;
  8439.         for(var i = 0; i < pending.length; i++) {
  8440.           pending[i]();
  8441.         }
  8442.         request.pending = null;
  8443.       };
  8444.  
  8445.       // if we have already resolved, pending is null, async call the callback
  8446.       request.wait = function(fn) {
  8447.         if (request.pending) {
  8448.           request.pending.push(fn);
  8449.         } else {
  8450.           endOfMicrotask(fn);
  8451.         }
  8452.       };
  8453.  
  8454.       return request;
  8455.     }
  8456.   };
  8457.  
  8458.   scope.Loader = Loader;
  8459. })(Polymer);
  8460.  
  8461. (function(scope) {
  8462.  
  8463. var urlResolver = scope.urlResolver;
  8464. var Loader = scope.Loader;
  8465.  
  8466. function StyleResolver() {
  8467.   this.loader = new Loader(this.regex);
  8468. }
  8469. StyleResolver.prototype = {
  8470.   regex: /@import\s+(?:url)?["'\(]*([^'"\)]*)['"\)]*;/g,
  8471.   // Recursively replace @imports with the text at that url
  8472.   resolve: function(text, url, callback) {
  8473.     var done = function(map) {
  8474.       callback(this.flatten(text, url, map));
  8475.     }.bind(this);
  8476.     this.loader.process(text, url, done);
  8477.   },
  8478.   // resolve the textContent of a style node
  8479.   resolveNode: function(style, url, callback) {
  8480.     var text = style.textContent;
  8481.     var done = function(text) {
  8482.       style.textContent = text;
  8483.       callback(style);
  8484.     };
  8485.     this.resolve(text, url, done);
  8486.   },
  8487.   // flatten all the @imports to text
  8488.   flatten: function(text, base, map) {
  8489.     var matches = this.loader.extractUrls(text, base);
  8490.     var match, url, intermediate;
  8491.     for (var i = 0; i < matches.length; i++) {
  8492.       match = matches[i];
  8493.       url = match.url;
  8494.       // resolve any css text to be relative to the importer, keep absolute url
  8495.       intermediate = urlResolver.resolveCssText(map[url], url, true);
  8496.       // flatten intermediate @imports
  8497.       intermediate = this.flatten(intermediate, base, map);
  8498.       text = text.replace(match.matched, intermediate);
  8499.     }
  8500.     return text;
  8501.   },
  8502.   loadStyles: function(styles, base, callback) {
  8503.     var loaded=0, l = styles.length;
  8504.     // called in the context of the style
  8505.     function loadedStyle(style) {
  8506.       loaded++;
  8507.       if (loaded === l && callback) {
  8508.         callback();
  8509.       }
  8510.     }
  8511.     for (var i=0, s; (i<l) && (s=styles[i]); i++) {
  8512.       this.resolveNode(s, base, loadedStyle);
  8513.     }
  8514.   }
  8515. };
  8516.  
  8517. var styleResolver = new StyleResolver();
  8518.  
  8519. // exports
  8520. scope.styleResolver = styleResolver;
  8521.  
  8522. })(Polymer);
  8523.  
  8524. (function(scope) {
  8525.  
  8526.   // copy own properties from 'api' to 'prototype, with name hinting for 'super'
  8527.   function extend(prototype, api) {
  8528.     if (prototype && api) {
  8529.       // use only own properties of 'api'
  8530.       Object.getOwnPropertyNames(api).forEach(function(n) {
  8531.         // acquire property descriptor
  8532.         var pd = Object.getOwnPropertyDescriptor(api, n);
  8533.         if (pd) {
  8534.           // clone property via descriptor
  8535.           Object.defineProperty(prototype, n, pd);
  8536.           // cache name-of-method for 'super' engine
  8537.           if (typeof pd.value == 'function') {
  8538.             // hint the 'super' engine
  8539.             pd.value.nom = n;
  8540.           }
  8541.         }
  8542.       });
  8543.     }
  8544.     return prototype;
  8545.   }
  8546.  
  8547.  
  8548.   // mixin
  8549.  
  8550.   // copy all properties from inProps (et al) to inObj
  8551.   function mixin(inObj/*, inProps, inMoreProps, ...*/) {
  8552.     var obj = inObj || {};
  8553.     for (var i = 1; i < arguments.length; i++) {
  8554.       var p = arguments[i];
  8555.       try {
  8556.         for (var n in p) {
  8557.           copyProperty(n, p, obj);
  8558.         }
  8559.       } catch(x) {
  8560.       }
  8561.     }
  8562.     return obj;
  8563.   }
  8564.  
  8565.   // copy property inName from inSource object to inTarget object
  8566.   function copyProperty(inName, inSource, inTarget) {
  8567.     var pd = getPropertyDescriptor(inSource, inName);
  8568.     Object.defineProperty(inTarget, inName, pd);
  8569.   }
  8570.  
  8571.   // get property descriptor for inName on inObject, even if
  8572.   // inName exists on some link in inObject's prototype chain
  8573.   function getPropertyDescriptor(inObject, inName) {
  8574.     if (inObject) {
  8575.       var pd = Object.getOwnPropertyDescriptor(inObject, inName);
  8576.       return pd || getPropertyDescriptor(Object.getPrototypeOf(inObject), inName);
  8577.     }
  8578.   }
  8579.  
  8580.   // exports
  8581.  
  8582.   scope.extend = extend;
  8583.   scope.mixin = mixin;
  8584.  
  8585.   // for bc
  8586.   Platform.mixin = mixin;
  8587.  
  8588. })(Polymer);
  8589.  
  8590. (function(scope) {
  8591.   
  8592.   // usage
  8593.   
  8594.   // invoke cb.call(this) in 100ms, unless the job is re-registered,
  8595.   // which resets the timer
  8596.   // 
  8597.   // this.myJob = this.job(this.myJob, cb, 100)
  8598.   //
  8599.   // returns a job handle which can be used to re-register a job
  8600.  
  8601.   var Job = function(inContext) {
  8602.     this.context = inContext;
  8603.     this.boundComplete = this.complete.bind(this)
  8604.   };
  8605.   Job.prototype = {
  8606.     go: function(callback, wait) {
  8607.       this.callback = callback;
  8608.       var h;
  8609.       if (!wait) {
  8610.         h = requestAnimationFrame(this.boundComplete);
  8611.         this.handle = function() {
  8612.           cancelAnimationFrame(h);
  8613.         }
  8614.       } else {
  8615.         h = setTimeout(this.boundComplete, wait);
  8616.         this.handle = function() {
  8617.           clearTimeout(h);
  8618.         }
  8619.       }
  8620.     },
  8621.     stop: function() {
  8622.       if (this.handle) {
  8623.         this.handle();
  8624.         this.handle = null;
  8625.       }
  8626.     },
  8627.     complete: function() {
  8628.       if (this.handle) {
  8629.         this.stop();
  8630.         this.callback.call(this.context);
  8631.       }
  8632.     }
  8633.   };
  8634.   
  8635.   function job(job, callback, wait) {
  8636.     if (job) {
  8637.       job.stop();
  8638.     } else {
  8639.       job = new Job(this);
  8640.     }
  8641.     job.go(callback, wait);
  8642.     return job;
  8643.   }
  8644.   
  8645.   // exports 
  8646.  
  8647.   scope.job = job;
  8648.   
  8649. })(Polymer);
  8650.  
  8651. (function(scope) {
  8652.  
  8653.   // dom polyfill, additions, and utility methods
  8654.  
  8655.   var registry = {};
  8656.  
  8657.   HTMLElement.register = function(tag, prototype) {
  8658.     registry[tag] = prototype;
  8659.   };
  8660.  
  8661.   // get prototype mapped to node <tag>
  8662.   HTMLElement.getPrototypeForTag = function(tag) {
  8663.     var prototype = !tag ? HTMLElement.prototype : registry[tag];
  8664.     // TODO(sjmiles): creating <tag> is likely to have wasteful side-effects
  8665.     return prototype || Object.getPrototypeOf(document.createElement(tag));
  8666.   };
  8667.  
  8668.   // we have to flag propagation stoppage for the event dispatcher
  8669.   var originalStopPropagation = Event.prototype.stopPropagation;
  8670.   Event.prototype.stopPropagation = function() {
  8671.     this.cancelBubble = true;
  8672.     originalStopPropagation.apply(this, arguments);
  8673.   };
  8674.   
  8675.   
  8676.   // polyfill DOMTokenList
  8677.   // * add/remove: allow these methods to take multiple classNames
  8678.   // * toggle: add a 2nd argument which forces the given state rather
  8679.   //  than toggling.
  8680.  
  8681.   var add = DOMTokenList.prototype.add;
  8682.   var remove = DOMTokenList.prototype.remove;
  8683.   DOMTokenList.prototype.add = function() {
  8684.     for (var i = 0; i < arguments.length; i++) {
  8685.       add.call(this, arguments[i]);
  8686.     }
  8687.   };
  8688.   DOMTokenList.prototype.remove = function() {
  8689.     for (var i = 0; i < arguments.length; i++) {
  8690.       remove.call(this, arguments[i]);
  8691.     }
  8692.   };
  8693.   DOMTokenList.prototype.toggle = function(name, bool) {
  8694.     if (arguments.length == 1) {
  8695.       bool = !this.contains(name);
  8696.     }
  8697.     bool ? this.add(name) : this.remove(name);
  8698.   };
  8699.   DOMTokenList.prototype.switch = function(oldName, newName) {
  8700.     oldName && this.remove(oldName);
  8701.     newName && this.add(newName);
  8702.   };
  8703.  
  8704.   // add array() to NodeList, NamedNodeMap, HTMLCollection
  8705.  
  8706.   var ArraySlice = function() {
  8707.     return Array.prototype.slice.call(this);
  8708.   };
  8709.  
  8710.   var namedNodeMap = (window.NamedNodeMap || window.MozNamedAttrMap || {});
  8711.  
  8712.   NodeList.prototype.array = ArraySlice;
  8713.   namedNodeMap.prototype.array = ArraySlice;
  8714.   HTMLCollection.prototype.array = ArraySlice;
  8715.  
  8716.   // utility
  8717.  
  8718.   function createDOM(inTagOrNode, inHTML, inAttrs) {
  8719.     var dom = typeof inTagOrNode == 'string' ?
  8720.         document.createElement(inTagOrNode) : inTagOrNode.cloneNode(true);
  8721.     dom.innerHTML = inHTML;
  8722.     if (inAttrs) {
  8723.       for (var n in inAttrs) {
  8724.         dom.setAttribute(n, inAttrs[n]);
  8725.       }
  8726.     }
  8727.     return dom;
  8728.   }
  8729.  
  8730.   // exports
  8731.  
  8732.   scope.createDOM = createDOM;
  8733.  
  8734. })(Polymer);
  8735.  
  8736. (function(scope) {
  8737.     // super
  8738.  
  8739.     // `arrayOfArgs` is an optional array of args like one might pass
  8740.     // to `Function.apply`
  8741.  
  8742.     // TODO(sjmiles):
  8743.     //    $super must be installed on an instance or prototype chain
  8744.     //    as `super`, and invoked via `this`, e.g.
  8745.     //      `this.super();`
  8746.  
  8747.     //    will not work if function objects are not unique, for example,
  8748.     //    when using mixins.
  8749.     //    The memoization strategy assumes each function exists on only one 
  8750.     //    prototype chain i.e. we use the function object for memoizing)
  8751.     //    perhaps we can bookkeep on the prototype itself instead
  8752.     function $super(arrayOfArgs) {
  8753.       // since we are thunking a method call, performance is important here: 
  8754.       // memoize all lookups, once memoized the fast path calls no other 
  8755.       // functions
  8756.       //
  8757.       // find the caller (cannot be `strict` because of 'caller')
  8758.       var caller = $super.caller;
  8759.       // memoized 'name of method' 
  8760.       var nom = caller.nom;
  8761.       // memoized next implementation prototype
  8762.       var _super = caller._super;
  8763.       if (!_super) {
  8764.         if (!nom) {
  8765.           nom = caller.nom = nameInThis.call(this, caller);
  8766.         }
  8767.         if (!nom) {
  8768.           console.warn('called super() on a method not installed declaratively (has no .nom property)');
  8769.         }
  8770.         // super prototype is either cached or we have to find it
  8771.         // by searching __proto__ (at the 'top')
  8772.         // invariant: because we cache _super on fn below, we never reach 
  8773.         // here from inside a series of calls to super(), so it's ok to 
  8774.         // start searching from the prototype of 'this' (at the 'top')
  8775.         // we must never memoize a null super for this reason
  8776.         _super = memoizeSuper(caller, nom, getPrototypeOf(this));
  8777.       }
  8778.       // our super function
  8779.       var fn = _super[nom];
  8780.       if (fn) {
  8781.         // memoize information so 'fn' can call 'super'
  8782.         if (!fn._super) {
  8783.           // must not memoize null, or we lose our invariant above
  8784.           memoizeSuper(fn, nom, _super);
  8785.         }
  8786.         // invoke the inherited method
  8787.         // if 'fn' is not function valued, this will throw
  8788.         return fn.apply(this, arrayOfArgs || []);
  8789.       }
  8790.     }
  8791.  
  8792.     function nameInThis(value) {
  8793.       var p = this.__proto__;
  8794.       while (p && p !== HTMLElement.prototype) {
  8795.         // TODO(sjmiles): getOwnPropertyNames is absurdly expensive
  8796.         var n$ = Object.getOwnPropertyNames(p);
  8797.         for (var i=0, l=n$.length, n; i<l && (n=n$[i]); i++) {
  8798.           var d = Object.getOwnPropertyDescriptor(p, n);
  8799.           if (typeof d.value === 'function' && d.value === value) {
  8800.             return n;
  8801.           }
  8802.         }
  8803.         p = p.__proto__;
  8804.       }
  8805.     }
  8806.  
  8807.     function memoizeSuper(method, name, proto) {
  8808.       // find and cache next prototype containing `name`
  8809.       // we need the prototype so we can do another lookup
  8810.       // from here
  8811.       var s = nextSuper(proto, name, method);
  8812.       if (s[name]) {
  8813.         // `s` is a prototype, the actual method is `s[name]`
  8814.         // tag super method with it's name for quicker lookups
  8815.         s[name].nom = name;
  8816.       }
  8817.       return method._super = s;
  8818.     }
  8819.  
  8820.     function nextSuper(proto, name, caller) {
  8821.       // look for an inherited prototype that implements name
  8822.       while (proto) {
  8823.         if ((proto[name] !== caller) && proto[name]) {
  8824.           return proto;
  8825.         }
  8826.         proto = getPrototypeOf(proto);
  8827.       }
  8828.       // must not return null, or we lose our invariant above
  8829.       // in this case, a super() call was invoked where no superclass
  8830.       // method exists
  8831.       // TODO(sjmiles): thow an exception?
  8832.       return Object;
  8833.     }
  8834.  
  8835.     // NOTE: In some platforms (IE10) the prototype chain is faked via 
  8836.     // __proto__. Therefore, always get prototype via __proto__ instead of
  8837.     // the more standard Object.getPrototypeOf.
  8838.     function getPrototypeOf(prototype) {
  8839.       return prototype.__proto__;
  8840.     }
  8841.  
  8842.     // utility function to precompute name tags for functions
  8843.     // in a (unchained) prototype
  8844.     function hintSuper(prototype) {
  8845.       // tag functions with their prototype name to optimize
  8846.       // super call invocations
  8847.       for (var n in prototype) {
  8848.         var pd = Object.getOwnPropertyDescriptor(prototype, n);
  8849.         if (pd && typeof pd.value === 'function') {
  8850.           pd.value.nom = n;
  8851.         }
  8852.       }
  8853.     }
  8854.  
  8855.     // exports
  8856.  
  8857.     scope.super = $super;
  8858.  
  8859. })(Polymer);
  8860.  
  8861. (function(scope) {
  8862.  
  8863.   function noopHandler(value) {
  8864.     return value;
  8865.   }
  8866.  
  8867.   // helper for deserializing properties of various types to strings
  8868.   var typeHandlers = {
  8869.     string: noopHandler,
  8870.     'undefined': noopHandler,
  8871.     date: function(value) {
  8872.       return new Date(Date.parse(value) || Date.now());
  8873.     },
  8874.     boolean: function(value) {
  8875.       if (value === '') {
  8876.         return true;
  8877.       }
  8878.       return value === 'false' ? false : !!value;
  8879.     },
  8880.     number: function(value) {
  8881.       var n = parseFloat(value);
  8882.       // hex values like "0xFFFF" parseFloat as 0
  8883.       if (n === 0) {
  8884.         n = parseInt(value);
  8885.       }
  8886.       return isNaN(n) ? value : n;
  8887.       // this code disabled because encoded values (like "0xFFFF")
  8888.       // do not round trip to their original format
  8889.       //return (String(floatVal) === value) ? floatVal : value;
  8890.     },
  8891.     object: function(value, currentValue) {
  8892.       if (currentValue === null) {
  8893.         return value;
  8894.       }
  8895.       try {
  8896.         // If the string is an object, we can parse is with the JSON library.
  8897.         // include convenience replace for single-quotes. If the author omits
  8898.         // quotes altogether, parse will fail.
  8899.         return JSON.parse(value.replace(/'/g, '"'));
  8900.       } catch(e) {
  8901.         // The object isn't valid JSON, return the raw value
  8902.         return value;
  8903.       }
  8904.     },
  8905.     // avoid deserialization of functions
  8906.     'function': function(value, currentValue) {
  8907.       return currentValue;
  8908.     }
  8909.   };
  8910.  
  8911.   function deserializeValue(value, currentValue) {
  8912.     // attempt to infer type from default value
  8913.     var inferredType = typeof currentValue;
  8914.     // invent 'date' type value for Date
  8915.     if (currentValue instanceof Date) {
  8916.       inferredType = 'date';
  8917.     }
  8918.     // delegate deserialization via type string
  8919.     return typeHandlers[inferredType](value, currentValue);
  8920.   }
  8921.  
  8922.   // exports
  8923.  
  8924.   scope.deserializeValue = deserializeValue;
  8925.  
  8926. })(Polymer);
  8927.  
  8928. (function(scope) {
  8929.  
  8930.   // imports
  8931.  
  8932.   var extend = scope.extend;
  8933.  
  8934.   // module
  8935.  
  8936.   var api = {};
  8937.  
  8938.   api.declaration = {};
  8939.   api.instance = {};
  8940.  
  8941.   api.publish = function(apis, prototype) {
  8942.     for (var n in apis) {
  8943.       extend(prototype, apis[n]);
  8944.     }
  8945.   };
  8946.  
  8947.   // exports
  8948.  
  8949.   scope.api = api;
  8950.  
  8951. })(Polymer);
  8952.  
  8953. (function(scope) {
  8954.  
  8955.   /**
  8956.    * @class polymer-base
  8957.    */
  8958.  
  8959.   var utils = {
  8960.  
  8961.     /**
  8962.       * Invokes a function asynchronously. The context of the callback
  8963.       * function is bound to 'this' automatically. Returns a handle which may 
  8964.       * be passed to <a href="#cancelAsync">cancelAsync</a> to cancel the 
  8965.       * asynchronous call.
  8966.       *
  8967.       * @method async
  8968.       * @param {Function|String} method
  8969.       * @param {any|Array} args
  8970.       * @param {number} timeout
  8971.       */
  8972.     async: function(method, args, timeout) {
  8973.       // when polyfilling Object.observe, ensure changes 
  8974.       // propagate before executing the async method
  8975.       Polymer.flush();
  8976.       // second argument to `apply` must be an array
  8977.       args = (args && args.length) ? args : [args];
  8978.       // function to invoke
  8979.       var fn = function() {
  8980.         (this[method] || method).apply(this, args);
  8981.       }.bind(this);
  8982.       // execute `fn` sooner or later
  8983.       var handle = timeout ? setTimeout(fn, timeout) :
  8984.           requestAnimationFrame(fn);
  8985.       // NOTE: switch on inverting handle to determine which time is used.
  8986.       return timeout ? handle : ~handle;
  8987.     },
  8988.  
  8989.     /**
  8990.       * Cancels a pending callback that was scheduled via 
  8991.       * <a href="#async">async</a>. 
  8992.       *
  8993.       * @method cancelAsync
  8994.       * @param {handle} handle Handle of the `async` to cancel.
  8995.       */
  8996.     cancelAsync: function(handle) {
  8997.       if (handle < 0) {
  8998.         cancelAnimationFrame(~handle);
  8999.       } else {
  9000.         clearTimeout(handle);
  9001.       }
  9002.     },
  9003.  
  9004.     /**
  9005.       * Fire an event.
  9006.       *
  9007.       * @method fire
  9008.       * @returns {Object} event
  9009.       * @param {string} type An event name.
  9010.       * @param {any} detail
  9011.       * @param {Node} onNode Target node.
  9012.       * @param {Boolean} bubbles Set false to prevent bubbling, defaults to true
  9013.       * @param {Boolean} cancelable Set false to prevent cancellation, defaults to true
  9014.       */
  9015.     fire: function(type, detail, onNode, bubbles, cancelable) {
  9016.       var node = onNode || this;
  9017.       var detail = detail === null || detail === undefined ? {} : detail;
  9018.       var event = new CustomEvent(type, {
  9019.         bubbles: bubbles !== undefined ? bubbles : true,
  9020.         cancelable: cancelable !== undefined ? cancelable : true,
  9021.         detail: detail
  9022.       });
  9023.       node.dispatchEvent(event);
  9024.       return event;
  9025.     },
  9026.  
  9027.     /**
  9028.       * Fire an event asynchronously.
  9029.       *
  9030.       * @method asyncFire
  9031.       * @param {string} type An event name.
  9032.       * @param detail
  9033.       * @param {Node} toNode Target node.
  9034.       */
  9035.     asyncFire: function(/*inType, inDetail*/) {
  9036.       this.async("fire", arguments);
  9037.     },
  9038.  
  9039.     /**
  9040.       * Remove class from old, add class to anew, if they exist.
  9041.       *
  9042.       * @param classFollows
  9043.       * @param anew A node.
  9044.       * @param old A node
  9045.       * @param className
  9046.       */
  9047.     classFollows: function(anew, old, className) {
  9048.       if (old) {
  9049.         old.classList.remove(className);
  9050.       }
  9051.       if (anew) {
  9052.         anew.classList.add(className);
  9053.       }
  9054.     },
  9055.  
  9056.     /**
  9057.       * Inject HTML which contains markup bound to this element into
  9058.       * a target element (replacing target element content).
  9059.       *
  9060.       * @param String html to inject
  9061.       * @param Element target element
  9062.       */
  9063.     injectBoundHTML: function(html, element) {
  9064.       var template = document.createElement('template');
  9065.       template.innerHTML = html;
  9066.       var fragment = this.instanceTemplate(template);
  9067.       if (element) {
  9068.         element.textContent = '';
  9069.         element.appendChild(fragment);
  9070.       }
  9071.       return fragment;
  9072.     }
  9073.   };
  9074.  
  9075.   // no-operation function for handy stubs
  9076.   var nop = function() {};
  9077.  
  9078.   // null-object for handy stubs
  9079.   var nob = {};
  9080.  
  9081.   // deprecated
  9082.  
  9083.   utils.asyncMethod = utils.async;
  9084.  
  9085.   // exports
  9086.  
  9087.   scope.api.instance.utils = utils;
  9088.   scope.nop = nop;
  9089.   scope.nob = nob;
  9090.  
  9091. })(Polymer);
  9092.  
  9093. (function(scope) {
  9094.  
  9095.   // imports
  9096.  
  9097.   var log = window.WebComponents ? WebComponents.flags.log : {};
  9098.   var EVENT_PREFIX = 'on-';
  9099.  
  9100.   // instance events api
  9101.   var events = {
  9102.     // read-only
  9103.     EVENT_PREFIX: EVENT_PREFIX,
  9104.     // event listeners on host
  9105.     addHostListeners: function() {
  9106.       var events = this.eventDelegates;
  9107.       log.events && (Object.keys(events).length > 0) && console.log('[%s] addHostListeners:', this.localName, events);
  9108.       // NOTE: host events look like bindings but really are not;
  9109.       // (1) we don't want the attribute to be set and (2) we want to support
  9110.       // multiple event listeners ('host' and 'instance') and Node.bind
  9111.       // by default supports 1 thing being bound.
  9112.       for (var type in events) {
  9113.         var methodName = events[type];
  9114.         PolymerGestures.addEventListener(this, type, this.element.getEventHandler(this, this, methodName));
  9115.       }
  9116.     },
  9117.     // call 'method' or function method on 'obj' with 'args', if the method exists
  9118.     dispatchMethod: function(obj, method, args) {
  9119.       if (obj) {
  9120.         log.events && console.group('[%s] dispatch [%s]', obj.localName, method);
  9121.         var fn = typeof method === 'function' ? method : obj[method];
  9122.         if (fn) {
  9123.           fn[args ? 'apply' : 'call'](obj, args);
  9124.         }
  9125.         log.events && console.groupEnd();
  9126.         // NOTE: dirty check right after calling method to ensure 
  9127.         // changes apply quickly; in a very complicated app using high 
  9128.         // frequency events, this can be a perf concern; in this case,
  9129.         // imperative handlers can be used to avoid flushing.
  9130.         Polymer.flush();
  9131.       }
  9132.     }
  9133.   };
  9134.  
  9135.   // exports
  9136.  
  9137.   scope.api.instance.events = events;
  9138.  
  9139.   /**
  9140.    * @class Polymer
  9141.    */
  9142.  
  9143.   /**
  9144.    * Add a gesture aware event handler to the given `node`. Can be used 
  9145.    * in place of `element.addEventListener` and ensures gestures will function
  9146.    * as expected on mobile platforms. Please note that Polymer's declarative
  9147.    * event handlers include this functionality by default.
  9148.    * 
  9149.    * @method addEventListener
  9150.    * @param {Node} node node on which to listen
  9151.    * @param {String} eventType name of the event
  9152.    * @param {Function} handlerFn event handler function
  9153.    * @param {Boolean} capture set to true to invoke event capturing
  9154.    * @type Function
  9155.    */
  9156.   // alias PolymerGestures event listener logic
  9157.   scope.addEventListener = function(node, eventType, handlerFn, capture) {
  9158.     PolymerGestures.addEventListener(wrap(node), eventType, handlerFn, capture);
  9159.   };
  9160.  
  9161.   /**
  9162.    * Remove a gesture aware event handler on the given `node`. To remove an
  9163.    * event listener, the exact same arguments are required that were passed
  9164.    * to `Polymer.addEventListener`.
  9165.    * 
  9166.    * @method removeEventListener
  9167.    * @param {Node} node node on which to listen
  9168.    * @param {String} eventType name of the event
  9169.    * @param {Function} handlerFn event handler function
  9170.    * @param {Boolean} capture set to true to invoke event capturing
  9171.    * @type Function
  9172.    */
  9173.   scope.removeEventListener = function(node, eventType, handlerFn, capture) {
  9174.     PolymerGestures.removeEventListener(wrap(node), eventType, handlerFn, capture);
  9175.   };
  9176.  
  9177. })(Polymer);
  9178.  
  9179. (function(scope) {
  9180.  
  9181.   // instance api for attributes
  9182.  
  9183.   var attributes = {
  9184.     // copy attributes defined in the element declaration to the instance
  9185.     // e.g. <polymer-element name="x-foo" tabIndex="0"> tabIndex is copied
  9186.     // to the element instance here.
  9187.     copyInstanceAttributes: function () {
  9188.       var a$ = this._instanceAttributes;
  9189.       for (var k in a$) {
  9190.         if (!this.hasAttribute(k)) {
  9191.           this.setAttribute(k, a$[k]);
  9192.         }
  9193.       }
  9194.     },
  9195.     // for each attribute on this, deserialize value to property as needed
  9196.     takeAttributes: function() {
  9197.       // if we have no publish lookup table, we have no attributes to take
  9198.       // TODO(sjmiles): ad hoc
  9199.       if (this._publishLC) {
  9200.         for (var i=0, a$=this.attributes, l=a$.length, a; (a=a$[i]) && i<l; i++) {
  9201.           this.attributeToProperty(a.name, a.value);
  9202.         }
  9203.       }
  9204.     },
  9205.     // if attribute 'name' is mapped to a property, deserialize
  9206.     // 'value' into that property
  9207.     attributeToProperty: function(name, value) {
  9208.       // try to match this attribute to a property (attributes are
  9209.       // all lower-case, so this is case-insensitive search)
  9210.       var name = this.propertyForAttribute(name);
  9211.       if (name) {
  9212.         // filter out 'mustached' values, these are to be
  9213.         // replaced with bound-data and are not yet values
  9214.         // themselves
  9215.         if (value && value.search(scope.bindPattern) >= 0) {
  9216.           return;
  9217.         }
  9218.         // get original value
  9219.         var currentValue = this[name];
  9220.         // deserialize Boolean or Number values from attribute
  9221.         var value = this.deserializeValue(value, currentValue);
  9222.         // only act if the value has changed
  9223.         if (value !== currentValue) {
  9224.           // install new value (has side-effects)
  9225.           this[name] = value;
  9226.         }
  9227.       }
  9228.     },
  9229.     // return the published property matching name, or undefined
  9230.     propertyForAttribute: function(name) {
  9231.       var match = this._publishLC && this._publishLC[name];
  9232.       return match;
  9233.     },
  9234.     // convert representation of `stringValue` based on type of `currentValue`
  9235.     deserializeValue: function(stringValue, currentValue) {
  9236.       return scope.deserializeValue(stringValue, currentValue);
  9237.     },
  9238.     // convert to a string value based on the type of `inferredType`
  9239.     serializeValue: function(value, inferredType) {
  9240.       if (inferredType === 'boolean') {
  9241.         return value ? '' : undefined;
  9242.       } else if (inferredType !== 'object' && inferredType !== 'function'
  9243.           && value !== undefined) {
  9244.         return value;
  9245.       }
  9246.     },
  9247.     // serializes `name` property value and updates the corresponding attribute
  9248.     // note that reflection is opt-in.
  9249.     reflectPropertyToAttribute: function(name) {
  9250.       var inferredType = typeof this[name];
  9251.       // try to intelligently serialize property value
  9252.       var serializedValue = this.serializeValue(this[name], inferredType);
  9253.       // boolean properties must reflect as boolean attributes
  9254.       if (serializedValue !== undefined) {
  9255.         this.setAttribute(name, serializedValue);
  9256.         // TODO(sorvell): we should remove attr for all properties
  9257.         // that have undefined serialization; however, we will need to
  9258.         // refine the attr reflection system to achieve this; pica, for example,
  9259.         // relies on having inferredType object properties not removed as
  9260.         // attrs.
  9261.       } else if (inferredType === 'boolean') {
  9262.         this.removeAttribute(name);
  9263.       }
  9264.     }
  9265.   };
  9266.  
  9267.   // exports
  9268.  
  9269.   scope.api.instance.attributes = attributes;
  9270.  
  9271. })(Polymer);
  9272.  
  9273. (function(scope) {
  9274.  
  9275.   /**
  9276.    * @class polymer-base
  9277.    */
  9278.  
  9279.   // imports
  9280.  
  9281.   var log = window.WebComponents ? WebComponents.flags.log : {};
  9282.  
  9283.   // magic words
  9284.  
  9285.   var OBSERVE_SUFFIX = 'Changed';
  9286.  
  9287.   // element api
  9288.  
  9289.   var empty = [];
  9290.  
  9291.   var updateRecord = {
  9292.     object: undefined,
  9293.     type: 'update',
  9294.     name: undefined,
  9295.     oldValue: undefined
  9296.   };
  9297.  
  9298.   var numberIsNaN = Number.isNaN || function(value) {
  9299.     return typeof value === 'number' && isNaN(value);
  9300.   };
  9301.  
  9302.   function areSameValue(left, right) {
  9303.     if (left === right)
  9304.       return left !== 0 || 1 / left === 1 / right;
  9305.     if (numberIsNaN(left) && numberIsNaN(right))
  9306.       return true;
  9307.     return left !== left && right !== right;
  9308.   }
  9309.  
  9310.   // capture A's value if B's value is null or undefined,
  9311.   // otherwise use B's value
  9312.   function resolveBindingValue(oldValue, value) {
  9313.     if (value === undefined && oldValue === null) {
  9314.       return value;
  9315.     }
  9316.     return (value === null || value === undefined) ? oldValue : value;
  9317.   }
  9318.  
  9319.   var properties = {
  9320.  
  9321.     // creates a CompoundObserver to observe property changes
  9322.     // NOTE, this is only done there are any properties in the `observe` object
  9323.     createPropertyObserver: function() {
  9324.       var n$ = this._observeNames;
  9325.       if (n$ && n$.length) {
  9326.         var o = this._propertyObserver = new CompoundObserver(true);
  9327.         this.registerObserver(o);
  9328.         // TODO(sorvell): may not be kosher to access the value here (this[n]);
  9329.         // previously we looked at the descriptor on the prototype
  9330.         // this doesn't work for inheritance and not for accessors without
  9331.         // a value property
  9332.         for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) {
  9333.           o.addPath(this, n);
  9334.           this.observeArrayValue(n, this[n], null);
  9335.         }
  9336.       }
  9337.     },
  9338.  
  9339.     // start observing property changes
  9340.     openPropertyObserver: function() {
  9341.       if (this._propertyObserver) {
  9342.         this._propertyObserver.open(this.notifyPropertyChanges, this);
  9343.       }
  9344.     },
  9345.  
  9346.     // handler for property changes; routes changes to observing methods
  9347.     // note: array valued properties are observed for array splices
  9348.     notifyPropertyChanges: function(newValues, oldValues, paths) {
  9349.       var name, method, called = {};
  9350.       for (var i in oldValues) {
  9351.         // note: paths is of form [object, path, object, path]
  9352.         name = paths[2 * i + 1];
  9353.         method = this.observe[name];
  9354.         if (method) {
  9355.           var ov = oldValues[i], nv = newValues[i];
  9356.           // observes the value if it is an array
  9357.           this.observeArrayValue(name, nv, ov);
  9358.           if (!called[method]) {
  9359.             // only invoke change method if one of ov or nv is not (undefined | null)
  9360.             if ((ov !== undefined && ov !== null) || (nv !== undefined && nv !== null)) {
  9361.               called[method] = true;
  9362.               // TODO(sorvell): call method with the set of values it's expecting;
  9363.               // e.g. 'foo bar': 'invalidate' expects the new and old values for
  9364.               // foo and bar. Currently we give only one of these and then
  9365.               // deliver all the arguments.
  9366.               this.invokeMethod(method, [ov, nv, arguments]);
  9367.             }
  9368.           }
  9369.         }
  9370.       }
  9371.     },
  9372.  
  9373.     // call method iff it exists.
  9374.     invokeMethod: function(method, args) {
  9375.       var fn = this[method] || method;
  9376.       if (typeof fn === 'function') {
  9377.         fn.apply(this, args);
  9378.       }
  9379.     },
  9380.  
  9381.     /**
  9382.      * Force any pending property changes to synchronously deliver to
  9383.      * handlers specified in the `observe` object.
  9384.      * Note, normally changes are processed at microtask time.
  9385.      *
  9386.      * @method deliverChanges
  9387.      */
  9388.     deliverChanges: function() {
  9389.       if (this._propertyObserver) {
  9390.         this._propertyObserver.deliver();
  9391.       }
  9392.     },
  9393.  
  9394.     observeArrayValue: function(name, value, old) {
  9395.       // we only care if there are registered side-effects
  9396.       var callbackName = this.observe[name];
  9397.       if (callbackName) {
  9398.         // if we are observing the previous value, stop
  9399.         if (Array.isArray(old)) {
  9400.           log.observe && console.log('[%s] observeArrayValue: unregister observer [%s]', this.localName, name);
  9401.           this.closeNamedObserver(name + '__array');
  9402.         }
  9403.         // if the new value is an array, being observing it
  9404.         if (Array.isArray(value)) {
  9405.           log.observe && console.log('[%s] observeArrayValue: register observer [%s]', this.localName, name, value);
  9406.           var observer = new ArrayObserver(value);
  9407.           observer.open(function(splices) {
  9408.             this.invokeMethod(callbackName, [splices]);
  9409.           }, this);
  9410.           this.registerNamedObserver(name + '__array', observer);
  9411.         }
  9412.       }
  9413.     },
  9414.  
  9415.     emitPropertyChangeRecord: function(name, value, oldValue) {
  9416.       var object = this;
  9417.       if (areSameValue(value, oldValue)) {
  9418.         return;
  9419.       }
  9420.       // invoke property change side effects
  9421.       this._propertyChanged(name, value, oldValue);
  9422.       // emit change record
  9423.       if (!Observer.hasObjectObserve) {
  9424.         return;
  9425.       }
  9426.       var notifier = this._objectNotifier;
  9427.       if (!notifier) {
  9428.         notifier = this._objectNotifier = Object.getNotifier(this);
  9429.       }
  9430.       updateRecord.object = this;
  9431.       updateRecord.name = name;
  9432.       updateRecord.oldValue = oldValue;
  9433.       notifier.notify(updateRecord);
  9434.     },
  9435.  
  9436.     _propertyChanged: function(name, value, oldValue) {
  9437.       if (this.reflect[name]) {
  9438.         this.reflectPropertyToAttribute(name);
  9439.       }
  9440.     },
  9441.  
  9442.     // creates a property binding (called via bind) to a published property.
  9443.     bindProperty: function(property, observable, oneTime) {
  9444.       if (oneTime) {
  9445.         this[property] = observable;
  9446.         return;
  9447.       }
  9448.       var computed = this.element.prototype.computed;
  9449.       // Binding an "out-only" value to a computed property. Note that
  9450.       // since this observer isn't opened, it doesn't need to be closed on
  9451.       // cleanup.
  9452.       if (computed && computed[property]) {
  9453.         var privateComputedBoundValue = property + 'ComputedBoundObservable_';
  9454.         this[privateComputedBoundValue] = observable;
  9455.         return;
  9456.       }
  9457.       return this.bindToAccessor(property, observable, resolveBindingValue);
  9458.     },
  9459.  
  9460.     // NOTE property `name` must be published. This makes it an accessor.
  9461.     bindToAccessor: function(name, observable, resolveFn) {
  9462.       var privateName = name + '_';
  9463.       var privateObservable  = name + 'Observable_';
  9464.       // Present for properties which are computed and published and have a
  9465.       // bound value.
  9466.       var privateComputedBoundValue = name + 'ComputedBoundObservable_';
  9467.       this[privateObservable] = observable;
  9468.       var oldValue = this[privateName];
  9469.       // observable callback
  9470.       var self = this;
  9471.       function updateValue(value, oldValue) {
  9472.         self[privateName] = value;
  9473.         var setObserveable = self[privateComputedBoundValue];
  9474.         if (setObserveable && typeof setObserveable.setValue == 'function') {
  9475.           setObserveable.setValue(value);
  9476.         }
  9477.         self.emitPropertyChangeRecord(name, value, oldValue);
  9478.       }
  9479.       // resolve initial value
  9480.       var value = observable.open(updateValue);
  9481.       if (resolveFn && !areSameValue(oldValue, value)) {
  9482.         var resolvedValue = resolveFn(oldValue, value);
  9483.         if (!areSameValue(value, resolvedValue)) {
  9484.           value = resolvedValue;
  9485.           if (observable.setValue) {
  9486.             observable.setValue(value);
  9487.           }
  9488.         }
  9489.       }
  9490.       updateValue(value, oldValue);
  9491.       // register and return observable
  9492.       var observer = {
  9493.         close: function() {
  9494.           observable.close();
  9495.           self[privateObservable] = undefined;
  9496.           self[privateComputedBoundValue] = undefined;
  9497.         }
  9498.       };
  9499.       this.registerObserver(observer);
  9500.       return observer;
  9501.     },
  9502.  
  9503.     createComputedProperties: function() {
  9504.       if (!this._computedNames) {
  9505.         return;
  9506.       }
  9507.       for (var i = 0; i < this._computedNames.length; i++) {
  9508.         var name = this._computedNames[i];
  9509.         var expressionText = this.computed[name];
  9510.         try {
  9511.           var expression = PolymerExpressions.getExpression(expressionText);
  9512.           var observable = expression.getBinding(this, this.element.syntax);
  9513.           this.bindToAccessor(name, observable);
  9514.         } catch (ex) {
  9515.           console.error('Failed to create computed property', ex);
  9516.         }
  9517.       }
  9518.     },
  9519.  
  9520.     // property bookkeeping
  9521.     registerObserver: function(observer) {
  9522.       if (!this._observers) {
  9523.         this._observers = [observer];
  9524.         return;
  9525.       }
  9526.       this._observers.push(observer);
  9527.     },
  9528.  
  9529.     closeObservers: function() {
  9530.       if (!this._observers) {
  9531.         return;
  9532.       }
  9533.       // observer array items are arrays of observers.
  9534.       var observers = this._observers;
  9535.       for (var i = 0; i < observers.length; i++) {
  9536.         var observer = observers[i];
  9537.         if (observer && typeof observer.close == 'function') {
  9538.           observer.close();
  9539.         }
  9540.       }
  9541.       this._observers = [];
  9542.     },
  9543.  
  9544.     // bookkeeping observers for memory management
  9545.     registerNamedObserver: function(name, observer) {
  9546.       var o$ = this._namedObservers || (this._namedObservers = {});
  9547.       o$[name] = observer;
  9548.     },
  9549.  
  9550.     closeNamedObserver: function(name) {
  9551.       var o$ = this._namedObservers;
  9552.       if (o$ && o$[name]) {
  9553.         o$[name].close();
  9554.         o$[name] = null;
  9555.         return true;
  9556.       }
  9557.     },
  9558.  
  9559.     closeNamedObservers: function() {
  9560.       if (this._namedObservers) {
  9561.         for (var i in this._namedObservers) {
  9562.           this.closeNamedObserver(i);
  9563.         }
  9564.         this._namedObservers = {};
  9565.       }
  9566.     }
  9567.  
  9568.   };
  9569.  
  9570.   // logging
  9571.   var LOG_OBSERVE = '[%s] watching [%s]';
  9572.   var LOG_OBSERVED = '[%s#%s] watch: [%s] now [%s] was [%s]';
  9573.   var LOG_CHANGED = '[%s#%s] propertyChanged: [%s] now [%s] was [%s]';
  9574.  
  9575.   // exports
  9576.  
  9577.   scope.api.instance.properties = properties;
  9578.  
  9579. })(Polymer);
  9580.  
  9581. (function(scope) {
  9582.  
  9583.   /**
  9584.    * @class polymer-base
  9585.    */
  9586.  
  9587.   // imports
  9588.  
  9589.   var log = window.WebComponents ? WebComponents.flags.log : {};
  9590.  
  9591.   // element api supporting mdv
  9592.   var mdv = {
  9593.  
  9594.     /**
  9595.      * Creates dom cloned from the given template, instantiating bindings
  9596.      * with this element as the template model and `PolymerExpressions` as the
  9597.      * binding delegate.
  9598.      *
  9599.      * @method instanceTemplate
  9600.      * @param {Template} template source template from which to create dom.
  9601.      */
  9602.     instanceTemplate: function(template) {
  9603.       // ensure template is decorated (lets' things like <tr template ...> work)
  9604.       HTMLTemplateElement.decorate(template);
  9605.       // ensure a default bindingDelegate
  9606.       var syntax = this.syntax || (!template.bindingDelegate &&
  9607.           this.element.syntax);
  9608.       var dom = template.createInstance(this, syntax);
  9609.       var observers = dom.bindings_;
  9610.       for (var i = 0; i < observers.length; i++) {
  9611.         this.registerObserver(observers[i]);
  9612.       }
  9613.       return dom;
  9614.     },
  9615.  
  9616.     // Called by TemplateBinding/NodeBind to setup a binding to the given
  9617.     // property. It's overridden here to support property bindings
  9618.     // in addition to attribute bindings that are supported by default.
  9619.     bind: function(name, observable, oneTime) {
  9620.       var property = this.propertyForAttribute(name);
  9621.       if (!property) {
  9622.         // TODO(sjmiles): this mixin method must use the special form
  9623.         // of `super` installed by `mixinMethod` in declaration/prototype.js
  9624.         return this.mixinSuper(arguments);
  9625.       } else {
  9626.         // use n-way Polymer binding
  9627.         var observer = this.bindProperty(property, observable, oneTime);
  9628.         // NOTE: reflecting binding information is typically required only for
  9629.         // tooling. It has a performance cost so it's opt-in in Node.bind.
  9630.         if (Platform.enableBindingsReflection && observer) {
  9631.           observer.path = observable.path_;
  9632.           this._recordBinding(property, observer);
  9633.         }
  9634.         if (this.reflect[property]) {
  9635.           this.reflectPropertyToAttribute(property);
  9636.         }
  9637.         return observer;
  9638.       }
  9639.     },
  9640.  
  9641.     _recordBinding: function(name, observer) {
  9642.       this.bindings_ = this.bindings_ || {};
  9643.       this.bindings_[name] = observer;
  9644.     },
  9645.  
  9646.     // Called by TemplateBinding when all bindings on an element have been 
  9647.     // executed. This signals that all element inputs have been gathered
  9648.     // and it's safe to ready the element, create shadow-root and start
  9649.     // data-observation.
  9650.     bindFinished: function() {
  9651.       this.makeElementReady();
  9652.     },
  9653.  
  9654.     // called at detached time to signal that an element's bindings should be
  9655.     // cleaned up. This is done asynchronously so that users have the chance
  9656.     // to call `cancelUnbindAll` to prevent unbinding.
  9657.     asyncUnbindAll: function() {
  9658.       if (!this._unbound) {
  9659.         log.unbind && console.log('[%s] asyncUnbindAll', this.localName);
  9660.         this._unbindAllJob = this.job(this._unbindAllJob, this.unbindAll, 0);
  9661.       }
  9662.     },
  9663.     
  9664.     /**
  9665.      * This method should rarely be used and only if 
  9666.      * <a href="#cancelUnbindAll">`cancelUnbindAll`</a> has been called to 
  9667.      * prevent element unbinding. In this case, the element's bindings will 
  9668.      * not be automatically cleaned up and it cannot be garbage collected 
  9669.      * by the system. If memory pressure is a concern or a 
  9670.      * large amount of elements need to be managed in this way, `unbindAll`
  9671.      * can be called to deactivate the element's bindings and allow its 
  9672.      * memory to be reclaimed.
  9673.      *
  9674.      * @method unbindAll
  9675.      */
  9676.     unbindAll: function() {
  9677.       if (!this._unbound) {
  9678.         this.closeObservers();
  9679.         this.closeNamedObservers();
  9680.         this._unbound = true;
  9681.       }
  9682.     },
  9683.  
  9684.     /**
  9685.      * Call in `detached` to prevent the element from unbinding when it is 
  9686.      * detached from the dom. The element is unbound as a cleanup step that 
  9687.      * allows its memory to be reclaimed. 
  9688.      * If `cancelUnbindAll` is used, consider calling 
  9689.      * <a href="#unbindAll">`unbindAll`</a> when the element is no longer
  9690.      * needed. This will allow its memory to be reclaimed.
  9691.      * 
  9692.      * @method cancelUnbindAll
  9693.      */
  9694.     cancelUnbindAll: function() {
  9695.       if (this._unbound) {
  9696.         log.unbind && console.warn('[%s] already unbound, cannot cancel unbindAll', this.localName);
  9697.         return;
  9698.       }
  9699.       log.unbind && console.log('[%s] cancelUnbindAll', this.localName);
  9700.       if (this._unbindAllJob) {
  9701.         this._unbindAllJob = this._unbindAllJob.stop();
  9702.       }
  9703.     }
  9704.  
  9705.   };
  9706.  
  9707.   function unbindNodeTree(node) {
  9708.     forNodeTree(node, _nodeUnbindAll);
  9709.   }
  9710.  
  9711.   function _nodeUnbindAll(node) {
  9712.     node.unbindAll();
  9713.   }
  9714.  
  9715.   function forNodeTree(node, callback) {
  9716.     if (node) {
  9717.       callback(node);
  9718.       for (var child = node.firstChild; child; child = child.nextSibling) {
  9719.         forNodeTree(child, callback);
  9720.       }
  9721.     }
  9722.   }
  9723.  
  9724.   var mustachePattern = /\{\{([^{}]*)}}/;
  9725.  
  9726.   // exports
  9727.  
  9728.   scope.bindPattern = mustachePattern;
  9729.   scope.api.instance.mdv = mdv;
  9730.  
  9731. })(Polymer);
  9732.  
  9733. (function(scope) {
  9734.  
  9735.   /**
  9736.    * Common prototype for all Polymer Elements.
  9737.    * 
  9738.    * @class polymer-base
  9739.    * @homepage polymer.github.io
  9740.    */
  9741.   var base = {
  9742.     /**
  9743.      * Tags this object as the canonical Base prototype.
  9744.      *
  9745.      * @property PolymerBase
  9746.      * @type boolean
  9747.      * @default true
  9748.      */
  9749.     PolymerBase: true,
  9750.  
  9751.     /**
  9752.      * Debounce signals. 
  9753.      * 
  9754.      * Call `job` to defer a named signal, and all subsequent matching signals, 
  9755.      * until a wait time has elapsed with no new signal.
  9756.      * 
  9757.      *     debouncedClickAction: function(e) {
  9758.      *       // processClick only when it's been 100ms since the last click
  9759.      *       this.job('click', function() {
  9760.      *        this.processClick;
  9761.      *       }, 100);
  9762.      *     }
  9763.      *
  9764.      * @method job
  9765.      * @param String {String} job A string identifier for the job to debounce.
  9766.      * @param Function {Function} callback A function that is called (with `this` context) when the wait time elapses.
  9767.      * @param Number {Number} wait Time in milliseconds (ms) after the last signal that must elapse before invoking `callback`
  9768.      * @type Handle
  9769.      */
  9770.     job: function(job, callback, wait) {
  9771.       if (typeof job === 'string') {
  9772.         var n = '___' + job;
  9773.         this[n] = Polymer.job.call(this, this[n], callback, wait);
  9774.       } else {
  9775.         // TODO(sjmiles): suggest we deprecate this call signature
  9776.         return Polymer.job.call(this, job, callback, wait);
  9777.       }
  9778.     },
  9779.  
  9780.     /**
  9781.      * Invoke a superclass method. 
  9782.      * 
  9783.      * Use `super()` to invoke the most recently overridden call to the 
  9784.      * currently executing function. 
  9785.      * 
  9786.      * To pass arguments through, use the literal `arguments` as the parameter 
  9787.      * to `super()`.
  9788.      *
  9789.      *     nextPageAction: function(e) {
  9790.      *       // invoke the superclass version of `nextPageAction`
  9791.      *       this.super(arguments); 
  9792.      *     }
  9793.      *
  9794.      * To pass custom arguments, arrange them in an array.
  9795.      *
  9796.      *     appendSerialNo: function(value, serial) {
  9797.      *       // prefix the superclass serial number with our lot # before
  9798.      *       // invoking the superlcass
  9799.      *       return this.super([value, this.lotNo + serial])
  9800.      *     }
  9801.      *
  9802.      * @method super
  9803.      * @type Any
  9804.      * @param {args) An array of arguments to use when calling the superclass method, or null.
  9805.      */
  9806.     super: Polymer.super,
  9807.  
  9808.     /**
  9809.      * Lifecycle method called when the element is instantiated.
  9810.      * 
  9811.      * Override `created` to perform custom create-time tasks. No need to call 
  9812.      * super-class `created` unless you are extending another Polymer element.
  9813.      * Created is called before the element creates `shadowRoot` or prepares
  9814.      * data-observation.
  9815.      * 
  9816.      * @method created
  9817.      * @type void
  9818.      */
  9819.     created: function() {
  9820.     },
  9821.  
  9822.     /**
  9823.      * Lifecycle method called when the element has populated it's `shadowRoot`,
  9824.      * prepared data-observation, and made itself ready for API interaction.
  9825.      * 
  9826.      * @method ready
  9827.      * @type void
  9828.      */
  9829.     ready: function() {
  9830.     },
  9831.  
  9832.     /**
  9833.      * Low-level lifecycle method called as part of standard Custom Elements
  9834.      * operation. Polymer implements this method to provide basic default 
  9835.      * functionality. For custom create-time tasks, implement `created` 
  9836.      * instead, which is called immediately after `createdCallback`. 
  9837.      * 
  9838.      * @method createdCallback
  9839.      */
  9840.     createdCallback: function() {
  9841.       if (this.templateInstance && this.templateInstance.model) {
  9842.         console.warn('Attributes on ' + this.localName + ' were data bound ' +
  9843.             'prior to Polymer upgrading the element. This may result in ' +
  9844.             'incorrect binding types.');
  9845.       }
  9846.       this.created();
  9847.       this.prepareElement();
  9848.       if (!this.ownerDocument.isStagingDocument) {
  9849.         this.makeElementReady();
  9850.       }
  9851.     },
  9852.  
  9853.     // system entry point, do not override
  9854.     prepareElement: function() {
  9855.       if (this._elementPrepared) {
  9856.         console.warn('Element already prepared', this.localName);
  9857.         return;
  9858.       }
  9859.       this._elementPrepared = true;
  9860.       // storage for shadowRoots info
  9861.       this.shadowRoots = {};
  9862.       // install property observers
  9863.       this.createPropertyObserver();
  9864.       this.openPropertyObserver();
  9865.       // install boilerplate attributes
  9866.       this.copyInstanceAttributes();
  9867.       // process input attributes
  9868.       this.takeAttributes();
  9869.       // add event listeners
  9870.       this.addHostListeners();
  9871.     },
  9872.  
  9873.     // system entry point, do not override
  9874.     makeElementReady: function() {
  9875.       if (this._readied) {
  9876.         return;
  9877.       }
  9878.       this._readied = true;
  9879.       this.createComputedProperties();
  9880.       this.parseDeclarations(this.__proto__);
  9881.       // NOTE: Support use of the `unresolved` attribute to help polyfill
  9882.       // custom elements' `:unresolved` feature.
  9883.       this.removeAttribute('unresolved');
  9884.       // user entry point
  9885.       this.ready();
  9886.     },
  9887.  
  9888.     /**
  9889.      * Low-level lifecycle method called as part of standard Custom Elements
  9890.      * operation. Polymer implements this method to provide basic default 
  9891.      * functionality. For custom tasks in your element, implement `attributeChanged` 
  9892.      * instead, which is called immediately after `attributeChangedCallback`. 
  9893.      * 
  9894.      * @method attributeChangedCallback
  9895.      */
  9896.     attributeChangedCallback: function(name, oldValue) {
  9897.       // TODO(sjmiles): adhoc filter
  9898.       if (name !== 'class' && name !== 'style') {
  9899.         this.attributeToProperty(name, this.getAttribute(name));
  9900.       }
  9901.       if (this.attributeChanged) {
  9902.         this.attributeChanged.apply(this, arguments);
  9903.       }
  9904.     },
  9905.  
  9906.     /**
  9907.      * Low-level lifecycle method called as part of standard Custom Elements
  9908.      * operation. Polymer implements this method to provide basic default 
  9909.      * functionality. For custom create-time tasks, implement `attached` 
  9910.      * instead, which is called immediately after `attachedCallback`. 
  9911.      * 
  9912.      * @method attachedCallback
  9913.      */
  9914.      attachedCallback: function() {
  9915.       // when the element is attached, prevent it from unbinding.
  9916.       this.cancelUnbindAll();
  9917.       // invoke user action
  9918.       if (this.attached) {
  9919.         this.attached();
  9920.       }
  9921.       if (!this.hasBeenAttached) {
  9922.         this.hasBeenAttached = true;
  9923.         if (this.domReady) {
  9924.           this.async('domReady');
  9925.         }
  9926.       }
  9927.     },
  9928.  
  9929.      /**
  9930.      * Implement to access custom elements in dom descendants, ancestors, 
  9931.      * or siblings. Because custom elements upgrade in document order, 
  9932.      * elements accessed in `ready` or `attached` may not be upgraded. When
  9933.      * `domReady` is called, all registered custom elements are guaranteed
  9934.      * to have been upgraded.
  9935.      * 
  9936.      * @method domReady
  9937.      */
  9938.  
  9939.     /**
  9940.      * Low-level lifecycle method called as part of standard Custom Elements
  9941.      * operation. Polymer implements this method to provide basic default 
  9942.      * functionality. For custom create-time tasks, implement `detached` 
  9943.      * instead, which is called immediately after `detachedCallback`. 
  9944.      * 
  9945.      * @method detachedCallback
  9946.      */
  9947.     detachedCallback: function() {
  9948.       if (!this.preventDispose) {
  9949.         this.asyncUnbindAll();
  9950.       }
  9951.       // invoke user action
  9952.       if (this.detached) {
  9953.         this.detached();
  9954.       }
  9955.       // TODO(sorvell): bc
  9956.       if (this.leftView) {
  9957.         this.leftView();
  9958.       }
  9959.     },
  9960.  
  9961.     /**
  9962.      * Walks the prototype-chain of this element and allows specific
  9963.      * classes a chance to process static declarations.
  9964.      * 
  9965.      * In particular, each polymer-element has it's own `template`.
  9966.      * `parseDeclarations` is used to accumulate all element `template`s
  9967.      * from an inheritance chain.
  9968.      *
  9969.      * `parseDeclaration` static methods implemented in the chain are called
  9970.      * recursively, oldest first, with the `<polymer-element>` associated
  9971.      * with the current prototype passed as an argument.
  9972.      * 
  9973.      * An element may override this method to customize shadow-root generation. 
  9974.      * 
  9975.      * @method parseDeclarations
  9976.      */
  9977.     parseDeclarations: function(p) {
  9978.       if (p && p.element) {
  9979.         this.parseDeclarations(p.__proto__);
  9980.         p.parseDeclaration.call(this, p.element);
  9981.       }
  9982.     },
  9983.  
  9984.     /**
  9985.      * Perform init-time actions based on static information in the
  9986.      * `<polymer-element>` instance argument.
  9987.      *
  9988.      * For example, the standard implementation locates the template associated
  9989.      * with the given `<polymer-element>` and stamps it into a shadow-root to
  9990.      * implement shadow inheritance.
  9991.      *  
  9992.      * An element may override this method for custom behavior. 
  9993.      * 
  9994.      * @method parseDeclaration
  9995.      */
  9996.     parseDeclaration: function(elementElement) {
  9997.       var template = this.fetchTemplate(elementElement);
  9998.       if (template) {
  9999.         var root = this.shadowFromTemplate(template);
  10000.         this.shadowRoots[elementElement.name] = root;
  10001.       }
  10002.     },
  10003.  
  10004.     /**
  10005.      * Given a `<polymer-element>`, find an associated template (if any) to be
  10006.      * used for shadow-root generation.
  10007.      *
  10008.      * An element may override this method for custom behavior. 
  10009.      * 
  10010.      * @method fetchTemplate
  10011.      */
  10012.     fetchTemplate: function(elementElement) {
  10013.       return elementElement.querySelector('template');
  10014.     },
  10015.  
  10016.     /**
  10017.      * Create a shadow-root in this host and stamp `template` as it's 
  10018.      * content. 
  10019.      *
  10020.      * An element may override this method for custom behavior. 
  10021.      * 
  10022.      * @method shadowFromTemplate
  10023.      */
  10024.     shadowFromTemplate: function(template) {
  10025.       if (template) {
  10026.         // make a shadow root
  10027.         var root = this.createShadowRoot();
  10028.         // stamp template
  10029.         // which includes parsing and applying MDV bindings before being
  10030.         // inserted (to avoid {{}} in attribute values)
  10031.         var dom = this.instanceTemplate(template);
  10032.         // append to shadow dom
  10033.         root.appendChild(dom);
  10034.         // perform post-construction initialization tasks on shadow root
  10035.         this.shadowRootReady(root, template);
  10036.         // return the created shadow root
  10037.         return root;
  10038.       }
  10039.     },
  10040.  
  10041.     // utility function that stamps a <template> into light-dom
  10042.     lightFromTemplate: function(template, refNode) {
  10043.       if (template) {
  10044.         // TODO(sorvell): mark this element as an eventController so that
  10045.         // event listeners on bound nodes inside it will be called on it.
  10046.         // Note, the expectation here is that events on all descendants
  10047.         // should be handled by this element.
  10048.         this.eventController = this;
  10049.         // stamp template
  10050.         // which includes parsing and applying MDV bindings before being
  10051.         // inserted (to avoid {{}} in attribute values)
  10052.         var dom = this.instanceTemplate(template);
  10053.         // append to shadow dom
  10054.         if (refNode) {
  10055.           this.insertBefore(dom, refNode);
  10056.         } else {
  10057.           this.appendChild(dom);
  10058.         }
  10059.         // perform post-construction initialization tasks on ahem, light root
  10060.         this.shadowRootReady(this);
  10061.         // return the created shadow root
  10062.         return dom;
  10063.       }
  10064.     },
  10065.  
  10066.     shadowRootReady: function(root) {
  10067.       // locate nodes with id and store references to them in this.$ hash
  10068.       this.marshalNodeReferences(root);
  10069.     },
  10070.  
  10071.     // locate nodes with id and store references to them in this.$ hash
  10072.     marshalNodeReferences: function(root) {
  10073.       // establish $ instance variable
  10074.       var $ = this.$ = this.$ || {};
  10075.       // populate $ from nodes with ID from the LOCAL tree
  10076.       if (root) {
  10077.         var n$ = root.querySelectorAll("[id]");
  10078.         for (var i=0, l=n$.length, n; (i<l) && (n=n$[i]); i++) {
  10079.           $[n.id] = n;
  10080.         };
  10081.       }
  10082.     },
  10083.  
  10084.     /**
  10085.      * Register a one-time callback when a child-list or sub-tree mutation
  10086.      * occurs on node. 
  10087.      *
  10088.      * For persistent callbacks, call onMutation from your listener. 
  10089.      * 
  10090.      * @method onMutation
  10091.      * @param Node {Node} node Node to watch for mutations.
  10092.      * @param Function {Function} listener Function to call on mutation. The function is invoked as `listener.call(this, observer, mutations);` where `observer` is the MutationObserver that triggered the notification, and `mutations` is the native mutation list.
  10093.      */
  10094.     onMutation: function(node, listener) {
  10095.       var observer = new MutationObserver(function(mutations) {
  10096.         listener.call(this, observer, mutations);
  10097.         observer.disconnect();
  10098.       }.bind(this));
  10099.       observer.observe(node, {childList: true, subtree: true});
  10100.     }
  10101.   };
  10102.  
  10103.   /**
  10104.    * @class Polymer
  10105.    */
  10106.   
  10107.   /**
  10108.    * Returns true if the object includes <a href="#polymer-base">polymer-base</a> in it's prototype chain.
  10109.    * 
  10110.    * @method isBase
  10111.    * @param Object {Object} object Object to test.
  10112.    * @type Boolean
  10113.    */
  10114.   function isBase(object) {
  10115.     return object.hasOwnProperty('PolymerBase')
  10116.   }
  10117.  
  10118.   // name a base constructor for dev tools
  10119.  
  10120.   /**
  10121.    * The Polymer base-class constructor.
  10122.    * 
  10123.    * @property Base
  10124.    * @type Function
  10125.    */
  10126.   function PolymerBase() {};
  10127.   PolymerBase.prototype = base;
  10128.   base.constructor = PolymerBase;
  10129.  
  10130.   // exports
  10131.  
  10132.   scope.Base = PolymerBase;
  10133.   scope.isBase = isBase;
  10134.   scope.api.instance.base = base;
  10135.  
  10136. })(Polymer);
  10137.  
  10138. (function(scope) {
  10139.  
  10140.   // imports
  10141.  
  10142.   var log = window.WebComponents ? WebComponents.flags.log : {};
  10143.   var hasShadowDOMPolyfill = window.ShadowDOMPolyfill;
  10144.  
  10145.   // magic words
  10146.   
  10147.   var STYLE_SCOPE_ATTRIBUTE = 'element';
  10148.   var STYLE_CONTROLLER_SCOPE = 'controller';
  10149.   
  10150.   var styles = {
  10151.     STYLE_SCOPE_ATTRIBUTE: STYLE_SCOPE_ATTRIBUTE,
  10152.     /**
  10153.      * Installs external stylesheets and <style> elements with the attribute 
  10154.      * polymer-scope='controller' into the scope of element. This is intended
  10155.      * to be a called during custom element construction.
  10156.     */
  10157.     installControllerStyles: function() {
  10158.       // apply controller styles, but only if they are not yet applied
  10159.       var scope = this.findStyleScope();
  10160.       if (scope && !this.scopeHasNamedStyle(scope, this.localName)) {
  10161.         // allow inherited controller styles
  10162.         var proto = getPrototypeOf(this), cssText = '';
  10163.         while (proto && proto.element) {
  10164.           cssText += proto.element.cssTextForScope(STYLE_CONTROLLER_SCOPE);
  10165.           proto = getPrototypeOf(proto);
  10166.         }
  10167.         if (cssText) {
  10168.           this.installScopeCssText(cssText, scope);
  10169.         }
  10170.       }
  10171.     },
  10172.     installScopeStyle: function(style, name, scope) {
  10173.       var scope = scope || this.findStyleScope(), name = name || '';
  10174.       if (scope && !this.scopeHasNamedStyle(scope, this.localName + name)) {
  10175.         var cssText = '';
  10176.         if (style instanceof Array) {
  10177.           for (var i=0, l=style.length, s; (i<l) && (s=style[i]); i++) {
  10178.             cssText += s.textContent + '\n\n';
  10179.           }
  10180.         } else {
  10181.           cssText = style.textContent;
  10182.         }
  10183.         this.installScopeCssText(cssText, scope, name);
  10184.       }
  10185.     },
  10186.     installScopeCssText: function(cssText, scope, name) {
  10187.       scope = scope || this.findStyleScope();
  10188.       name = name || '';
  10189.       if (!scope) {
  10190.         return;
  10191.       }
  10192.       if (hasShadowDOMPolyfill) {
  10193.         cssText = shimCssText(cssText, scope.host);
  10194.       }
  10195.       var style = this.element.cssTextToScopeStyle(cssText,
  10196.           STYLE_CONTROLLER_SCOPE);
  10197.       Polymer.applyStyleToScope(style, scope);
  10198.       // cache that this style has been applied
  10199.       this.styleCacheForScope(scope)[this.localName + name] = true;
  10200.     },
  10201.     findStyleScope: function(node) {
  10202.       // find the shadow root that contains this element
  10203.       var n = node || this;
  10204.       while (n.parentNode) {
  10205.         n = n.parentNode;
  10206.       }
  10207.       return n;
  10208.     },
  10209.     scopeHasNamedStyle: function(scope, name) {
  10210.       var cache = this.styleCacheForScope(scope);
  10211.       return cache[name];
  10212.     },
  10213.     styleCacheForScope: function(scope) {
  10214.       if (hasShadowDOMPolyfill) {
  10215.         var scopeName = scope.host ? scope.host.localName : scope.localName;
  10216.         return polyfillScopeStyleCache[scopeName] || (polyfillScopeStyleCache[scopeName] = {});
  10217.       } else {
  10218.         return scope._scopeStyles = (scope._scopeStyles || {});
  10219.       }
  10220.     }
  10221.   };
  10222.  
  10223.   var polyfillScopeStyleCache = {};
  10224.   
  10225.   // NOTE: use raw prototype traversal so that we ensure correct traversal
  10226.   // on platforms where the protoype chain is simulated via __proto__ (IE10)
  10227.   function getPrototypeOf(prototype) {
  10228.     return prototype.__proto__;
  10229.   }
  10230.  
  10231.   function shimCssText(cssText, host) {
  10232.     var name = '', is = false;
  10233.     if (host) {
  10234.       name = host.localName;
  10235.       is = host.hasAttribute('is');
  10236.     }
  10237.     var selector = WebComponents.ShadowCSS.makeScopeSelector(name, is);
  10238.     return WebComponents.ShadowCSS.shimCssText(cssText, selector);
  10239.   }
  10240.  
  10241.   // exports
  10242.  
  10243.   scope.api.instance.styles = styles;
  10244.   
  10245. })(Polymer);
  10246.  
  10247. (function(scope) {
  10248.  
  10249.   // imports
  10250.  
  10251.   var extend = scope.extend;
  10252.   var api = scope.api;
  10253.  
  10254.   // imperative implementation: Polymer()
  10255.  
  10256.   // specify an 'own' prototype for tag `name`
  10257.   function element(name, prototype) {
  10258.     if (typeof name !== 'string') {
  10259.       var script = prototype || document._currentScript;
  10260.       prototype = name;
  10261.       name = script && script.parentNode && script.parentNode.getAttribute ?
  10262.           script.parentNode.getAttribute('name') : '';
  10263.       if (!name) {
  10264.         throw 'Element name could not be inferred.';
  10265.       }
  10266.     }
  10267.     if (getRegisteredPrototype(name)) {
  10268.       throw 'Already registered (Polymer) prototype for element ' + name;
  10269.     }
  10270.     // cache the prototype
  10271.     registerPrototype(name, prototype);
  10272.     // notify the registrar waiting for 'name', if any
  10273.     notifyPrototype(name);
  10274.   }
  10275.  
  10276.   // async prototype source
  10277.  
  10278.   function waitingForPrototype(name, client) {
  10279.     waitPrototype[name] = client;
  10280.   }
  10281.  
  10282.   var waitPrototype = {};
  10283.  
  10284.   function notifyPrototype(name) {
  10285.     if (waitPrototype[name]) {
  10286.       waitPrototype[name].registerWhenReady();
  10287.       delete waitPrototype[name];
  10288.     }
  10289.   }
  10290.  
  10291.   // utility and bookkeeping
  10292.  
  10293.   // maps tag names to prototypes, as registered with
  10294.   // Polymer. Prototypes associated with a tag name
  10295.   // using document.registerElement are available from
  10296.   // HTMLElement.getPrototypeForTag().
  10297.   // If an element was fully registered by Polymer, then
  10298.   // Polymer.getRegisteredPrototype(name) === 
  10299.   //   HTMLElement.getPrototypeForTag(name)
  10300.  
  10301.   var prototypesByName = {};
  10302.  
  10303.   function registerPrototype(name, prototype) {
  10304.     return prototypesByName[name] = prototype || {};
  10305.   }
  10306.  
  10307.   function getRegisteredPrototype(name) {
  10308.     return prototypesByName[name];
  10309.   }
  10310.  
  10311.   function instanceOfType(element, type) {
  10312.     if (typeof type !== 'string') {
  10313.       return false;
  10314.     }
  10315.     var proto = HTMLElement.getPrototypeForTag(type);
  10316.     var ctor = proto && proto.constructor;
  10317.     if (!ctor) {
  10318.       return false;
  10319.     }
  10320.     if (CustomElements.instanceof) {
  10321.       return CustomElements.instanceof(element, ctor);
  10322.     }
  10323.     return element instanceof ctor;
  10324.   }
  10325.  
  10326.   // exports
  10327.  
  10328.   scope.getRegisteredPrototype = getRegisteredPrototype;
  10329.   scope.waitingForPrototype = waitingForPrototype;
  10330.   scope.instanceOfType = instanceOfType;
  10331.  
  10332.   // namespace shenanigans so we can expose our scope on the registration 
  10333.   // function
  10334.  
  10335.   // make window.Polymer reference `element()`
  10336.  
  10337.   window.Polymer = element;
  10338.  
  10339.   // TODO(sjmiles): find a way to do this that is less terrible
  10340.   // copy window.Polymer properties onto `element()`
  10341.  
  10342.   extend(Polymer, scope);
  10343.  
  10344.   // Under the HTMLImports polyfill, scripts in the main document
  10345.   // do not block on imports; we want to allow calls to Polymer in the main
  10346.   // document. WebComponents collects those calls until we can process them, which
  10347.   // we do here.
  10348.  
  10349.   if (WebComponents.consumeDeclarations) {
  10350.     WebComponents.consumeDeclarations(function(declarations) {
  10351.       if (declarations) {
  10352.         for (var i=0, l=declarations.length, d; (i<l) && (d=declarations[i]); i++) {
  10353.           element.apply(null, d);
  10354.         }
  10355.       }
  10356.     });
  10357.   }
  10358.  
  10359. })(Polymer);
  10360.  
  10361. (function(scope) {
  10362.  
  10363. /**
  10364.  * @class polymer-base
  10365.  */
  10366.  
  10367.  /**
  10368.   * Resolve a url path to be relative to a `base` url. If unspecified, `base`
  10369.   * defaults to the element's ownerDocument url. Can be used to resolve
  10370.   * paths from element's in templates loaded in HTMLImports to be relative
  10371.   * to the document containing the element. Polymer automatically does this for
  10372.   * url attributes in element templates; however, if a url, for
  10373.   * example, contains a binding, then `resolvePath` can be used to ensure it is 
  10374.   * relative to the element document. For example, in an element's template,
  10375.   *
  10376.   *     <a href="{{resolvePath(path)}}">Resolved</a>
  10377.   * 
  10378.   * @method resolvePath
  10379.   * @param {String} url Url path to resolve.
  10380.   * @param {String} base Optional base url against which to resolve, defaults
  10381.   * to the element's ownerDocument url.
  10382.   * returns {String} resolved url.
  10383.   */
  10384.  
  10385. var path = {
  10386.   resolveElementPaths: function(node) {
  10387.     Polymer.urlResolver.resolveDom(node);
  10388.   },
  10389.   addResolvePathApi: function() {
  10390.     // let assetpath attribute modify the resolve path
  10391.     var assetPath = this.getAttribute('assetpath') || '';
  10392.     var root = new URL(assetPath, this.ownerDocument.baseURI);
  10393.     this.prototype.resolvePath = function(urlPath, base) {
  10394.       var u = new URL(urlPath, base || root);
  10395.       return u.href;
  10396.     };
  10397.   }
  10398. };
  10399.  
  10400. // exports
  10401. scope.api.declaration.path = path;
  10402.  
  10403. })(Polymer);
  10404.  
  10405. (function(scope) {
  10406.  
  10407.   // imports
  10408.  
  10409.   var log = window.WebComponents ? WebComponents.flags.log : {};
  10410.   var api = scope.api.instance.styles;
  10411.   var STYLE_SCOPE_ATTRIBUTE = api.STYLE_SCOPE_ATTRIBUTE;
  10412.  
  10413.   var hasShadowDOMPolyfill = window.ShadowDOMPolyfill;
  10414.  
  10415.   // magic words
  10416.  
  10417.   var STYLE_SELECTOR = 'style';
  10418.   var STYLE_LOADABLE_MATCH = '@import';
  10419.   var SHEET_SELECTOR = 'link[rel=stylesheet]';
  10420.   var STYLE_GLOBAL_SCOPE = 'global';
  10421.   var SCOPE_ATTR = 'polymer-scope';
  10422.  
  10423.   var styles = {
  10424.     // returns true if resources are loading
  10425.     loadStyles: function(callback) {
  10426.       var template = this.fetchTemplate();
  10427.       var content = template && this.templateContent();
  10428.       if (content) {
  10429.         this.convertSheetsToStyles(content);
  10430.         var styles = this.findLoadableStyles(content);
  10431.         if (styles.length) {
  10432.           var templateUrl = template.ownerDocument.baseURI;
  10433.           return Polymer.styleResolver.loadStyles(styles, templateUrl, callback);
  10434.         }
  10435.       }
  10436.       if (callback) {
  10437.         callback();
  10438.       }
  10439.     },
  10440.     convertSheetsToStyles: function(root) {
  10441.       var s$ = root.querySelectorAll(SHEET_SELECTOR);
  10442.       for (var i=0, l=s$.length, s, c; (i<l) && (s=s$[i]); i++) {
  10443.         c = createStyleElement(importRuleForSheet(s, this.ownerDocument.baseURI),
  10444.             this.ownerDocument);
  10445.         this.copySheetAttributes(c, s);
  10446.         s.parentNode.replaceChild(c, s);
  10447.       }
  10448.     },
  10449.     copySheetAttributes: function(style, link) {
  10450.       for (var i=0, a$=link.attributes, l=a$.length, a; (a=a$[i]) && i<l; i++) {
  10451.         if (a.name !== 'rel' && a.name !== 'href') {
  10452.           style.setAttribute(a.name, a.value);
  10453.         }
  10454.       }
  10455.     },
  10456.     findLoadableStyles: function(root) {
  10457.       var loadables = [];
  10458.       if (root) {
  10459.         var s$ = root.querySelectorAll(STYLE_SELECTOR);
  10460.         for (var i=0, l=s$.length, s; (i<l) && (s=s$[i]); i++) {
  10461.           if (s.textContent.match(STYLE_LOADABLE_MATCH)) {
  10462.             loadables.push(s);
  10463.           }
  10464.         }
  10465.       }
  10466.       return loadables;
  10467.     },
  10468.     /**
  10469.      * Install external stylesheets loaded in <polymer-element> elements into the 
  10470.      * element's template.
  10471.      * @param elementElement The <element> element to style.
  10472.      */
  10473.     installSheets: function() {
  10474.       this.cacheSheets();
  10475.       this.cacheStyles();
  10476.       this.installLocalSheets();
  10477.       this.installGlobalStyles();
  10478.     },
  10479.     /**
  10480.      * Remove all sheets from element and store for later use.
  10481.      */
  10482.     cacheSheets: function() {
  10483.       this.sheets = this.findNodes(SHEET_SELECTOR);
  10484.       this.sheets.forEach(function(s) {
  10485.         if (s.parentNode) {
  10486.           s.parentNode.removeChild(s);
  10487.         }
  10488.       });
  10489.     },
  10490.     cacheStyles: function() {
  10491.       this.styles = this.findNodes(STYLE_SELECTOR + '[' + SCOPE_ATTR + ']');
  10492.       this.styles.forEach(function(s) {
  10493.         if (s.parentNode) {
  10494.           s.parentNode.removeChild(s);
  10495.         }
  10496.       });
  10497.     },
  10498.     /**
  10499.      * Takes external stylesheets loaded in an <element> element and moves
  10500.      * their content into a <style> element inside the <element>'s template.
  10501.      * The sheet is then removed from the <element>. This is done only so 
  10502.      * that if the element is loaded in the main document, the sheet does
  10503.      * not become active.
  10504.      * Note, ignores sheets with the attribute 'polymer-scope'.
  10505.      * @param elementElement The <element> element to style.
  10506.      */
  10507.     installLocalSheets: function () {
  10508.       var sheets = this.sheets.filter(function(s) {
  10509.         return !s.hasAttribute(SCOPE_ATTR);
  10510.       });
  10511.       var content = this.templateContent();
  10512.       if (content) {
  10513.         var cssText = '';
  10514.         sheets.forEach(function(sheet) {
  10515.           cssText += cssTextFromSheet(sheet) + '\n';
  10516.         });
  10517.         if (cssText) {
  10518.           var style = createStyleElement(cssText, this.ownerDocument);
  10519.           content.insertBefore(style, content.firstChild);
  10520.         }
  10521.       }
  10522.     },
  10523.     findNodes: function(selector, matcher) {
  10524.       var nodes = this.querySelectorAll(selector).array();
  10525.       var content = this.templateContent();
  10526.       if (content) {
  10527.         var templateNodes = content.querySelectorAll(selector).array();
  10528.         nodes = nodes.concat(templateNodes);
  10529.       }
  10530.       return matcher ? nodes.filter(matcher) : nodes;
  10531.     },
  10532.     /**
  10533.      * Promotes external stylesheets and <style> elements with the attribute 
  10534.      * polymer-scope='global' into global scope.
  10535.      * This is particularly useful for defining @keyframe rules which 
  10536.      * currently do not function in scoped or shadow style elements.
  10537.      * (See wkb.ug/72462)
  10538.      * @param elementElement The <element> element to style.
  10539.     */
  10540.     // TODO(sorvell): remove when wkb.ug/72462 is addressed.
  10541.     installGlobalStyles: function() {
  10542.       var style = this.styleForScope(STYLE_GLOBAL_SCOPE);
  10543.       applyStyleToScope(style, document.head);
  10544.     },
  10545.     cssTextForScope: function(scopeDescriptor) {
  10546.       var cssText = '';
  10547.       // handle stylesheets
  10548.       var selector = '[' + SCOPE_ATTR + '=' + scopeDescriptor + ']';
  10549.       var matcher = function(s) {
  10550.         return matchesSelector(s, selector);
  10551.       };
  10552.       var sheets = this.sheets.filter(matcher);
  10553.       sheets.forEach(function(sheet) {
  10554.         cssText += cssTextFromSheet(sheet) + '\n\n';
  10555.       });
  10556.       // handle cached style elements
  10557.       var styles = this.styles.filter(matcher);
  10558.       styles.forEach(function(style) {
  10559.         cssText += style.textContent + '\n\n';
  10560.       });
  10561.       return cssText;
  10562.     },
  10563.     styleForScope: function(scopeDescriptor) {
  10564.       var cssText = this.cssTextForScope(scopeDescriptor);
  10565.       return this.cssTextToScopeStyle(cssText, scopeDescriptor);
  10566.     },
  10567.     cssTextToScopeStyle: function(cssText, scopeDescriptor) {
  10568.       if (cssText) {
  10569.         var style = createStyleElement(cssText);
  10570.         style.setAttribute(STYLE_SCOPE_ATTRIBUTE, this.getAttribute('name') +
  10571.             '-' + scopeDescriptor);
  10572.         return style;
  10573.       }
  10574.     }
  10575.   };
  10576.  
  10577.   function importRuleForSheet(sheet, baseUrl) {
  10578.     var href = new URL(sheet.getAttribute('href'), baseUrl).href;
  10579.     return '@import \'' + href + '\';';
  10580.   }
  10581.  
  10582.   function applyStyleToScope(style, scope) {
  10583.     if (style) {
  10584.       if (scope === document) {
  10585.         scope = document.head;
  10586.       }
  10587.       if (hasShadowDOMPolyfill) {
  10588.         scope = document.head;
  10589.       }
  10590.       // TODO(sorvell): necessary for IE
  10591.       // see https://connect.microsoft.com/IE/feedback/details/790212/
  10592.       // cloning-a-style-element-and-adding-to-document-produces
  10593.       // -unexpected-result#details
  10594.       // var clone = style.cloneNode(true);
  10595.       var clone = createStyleElement(style.textContent);
  10596.       var attr = style.getAttribute(STYLE_SCOPE_ATTRIBUTE);
  10597.       if (attr) {
  10598.         clone.setAttribute(STYLE_SCOPE_ATTRIBUTE, attr);
  10599.       }
  10600.       // TODO(sorvell): probably too brittle; try to figure out 
  10601.       // where to put the element.
  10602.       var refNode = scope.firstElementChild;
  10603.       if (scope === document.head) {
  10604.         var selector = 'style[' + STYLE_SCOPE_ATTRIBUTE + ']';
  10605.         var s$ = document.head.querySelectorAll(selector);
  10606.         if (s$.length) {
  10607.           refNode = s$[s$.length-1].nextElementSibling;
  10608.         }
  10609.       }
  10610.       scope.insertBefore(clone, refNode);
  10611.     }
  10612.   }
  10613.  
  10614.   function createStyleElement(cssText, scope) {
  10615.     scope = scope || document;
  10616.     scope = scope.createElement ? scope : scope.ownerDocument;
  10617.     var style = scope.createElement('style');
  10618.     style.textContent = cssText;
  10619.     return style;
  10620.   }
  10621.  
  10622.   function cssTextFromSheet(sheet) {
  10623.     return (sheet && sheet.__resource) || '';
  10624.   }
  10625.  
  10626.   function matchesSelector(node, inSelector) {
  10627.     if (matches) {
  10628.       return matches.call(node, inSelector);
  10629.     }
  10630.   }
  10631.   var p = HTMLElement.prototype;
  10632.   var matches = p.matches || p.matchesSelector || p.webkitMatchesSelector 
  10633.       || p.mozMatchesSelector;
  10634.   
  10635.   // exports
  10636.  
  10637.   scope.api.declaration.styles = styles;
  10638.   scope.applyStyleToScope = applyStyleToScope;
  10639.   
  10640. })(Polymer);
  10641.  
  10642. (function(scope) {
  10643.  
  10644.   // imports
  10645.  
  10646.   var log = window.WebComponents ? WebComponents.flags.log : {};
  10647.   var api = scope.api.instance.events;
  10648.   var EVENT_PREFIX = api.EVENT_PREFIX;
  10649.  
  10650.   var mixedCaseEventTypes = {};
  10651.   [
  10652.     'webkitAnimationStart',
  10653.     'webkitAnimationEnd',
  10654.     'webkitTransitionEnd',
  10655.     'DOMFocusOut',
  10656.     'DOMFocusIn',
  10657.     'DOMMouseScroll'
  10658.   ].forEach(function(e) {
  10659.     mixedCaseEventTypes[e.toLowerCase()] = e;
  10660.   });
  10661.  
  10662.   // polymer-element declarative api: events feature
  10663.   var events = {
  10664.     parseHostEvents: function() {
  10665.       // our delegates map
  10666.       var delegates = this.prototype.eventDelegates;
  10667.       // extract data from attributes into delegates
  10668.       this.addAttributeDelegates(delegates);
  10669.     },
  10670.     addAttributeDelegates: function(delegates) {
  10671.       // for each attribute
  10672.       for (var i=0, a; a=this.attributes[i]; i++) {
  10673.         // does it have magic marker identifying it as an event delegate?
  10674.         if (this.hasEventPrefix(a.name)) {
  10675.           // if so, add the info to delegates
  10676.           delegates[this.removeEventPrefix(a.name)] = a.value.replace('{{', '')
  10677.               .replace('}}', '').trim();
  10678.         }
  10679.       }
  10680.     },
  10681.     // starts with 'on-'
  10682.     hasEventPrefix: function (n) {
  10683.       return n && (n[0] === 'o') && (n[1] === 'n') && (n[2] === '-');
  10684.     },
  10685.     removeEventPrefix: function(n) {
  10686.       return n.slice(prefixLength);
  10687.     },
  10688.     findController: function(node) {
  10689.       while (node.parentNode) {
  10690.         if (node.eventController) {
  10691.           return node.eventController;
  10692.         }
  10693.         node = node.parentNode;
  10694.       }
  10695.       return node.host;
  10696.     },
  10697.     getEventHandler: function(controller, target, method) {
  10698.       var events = this;
  10699.       return function(e) {
  10700.         if (!controller || !controller.PolymerBase) {
  10701.           controller = events.findController(target);
  10702.         }
  10703.  
  10704.         var args = [e, e.detail, e.currentTarget];
  10705.         controller.dispatchMethod(controller, method, args);
  10706.       };
  10707.     },
  10708.     prepareEventBinding: function(pathString, name, node) {
  10709.       if (!this.hasEventPrefix(name))
  10710.         return;
  10711.  
  10712.       var eventType = this.removeEventPrefix(name);
  10713.       eventType = mixedCaseEventTypes[eventType] || eventType;
  10714.  
  10715.       var events = this;
  10716.  
  10717.       return function(model, node, oneTime) {
  10718.         var handler = events.getEventHandler(undefined, node, pathString);
  10719.         PolymerGestures.addEventListener(node, eventType, handler);
  10720.  
  10721.         if (oneTime)
  10722.           return;
  10723.  
  10724.         // TODO(rafaelw): This is really pointless work. Aside from the cost
  10725.         // of these allocations, NodeBind is going to setAttribute back to its
  10726.         // current value. Fixing this would mean changing the TemplateBinding
  10727.         // binding delegate API.
  10728.         function bindingValue() {
  10729.           return '{{ ' + pathString + ' }}';
  10730.         }
  10731.  
  10732.         return {
  10733.           open: bindingValue,
  10734.           discardChanges: bindingValue,
  10735.           close: function() {
  10736.             PolymerGestures.removeEventListener(node, eventType, handler);
  10737.           }
  10738.         };
  10739.       };
  10740.     }
  10741.   };
  10742.  
  10743.   var prefixLength = EVENT_PREFIX.length;
  10744.  
  10745.   // exports
  10746.   scope.api.declaration.events = events;
  10747.  
  10748. })(Polymer);
  10749.  
  10750. (function(scope) {
  10751.  
  10752.   // element api
  10753.  
  10754.   var observationBlacklist = ['attribute'];
  10755.  
  10756.   var properties = {
  10757.     inferObservers: function(prototype) {
  10758.       // called before prototype.observe is chained to inherited object
  10759.       var observe = prototype.observe, property;
  10760.       for (var n in prototype) {
  10761.         if (n.slice(-7) === 'Changed') {
  10762.           property = n.slice(0, -7);
  10763.           if (this.canObserveProperty(property)) {
  10764.             if (!observe) {
  10765.               observe  = (prototype.observe = {});
  10766.             }
  10767.             observe[property] = observe[property] || n;
  10768.           }
  10769.         }
  10770.       }
  10771.     },
  10772.     canObserveProperty: function(property) {
  10773.       return (observationBlacklist.indexOf(property) < 0);
  10774.     },
  10775.     explodeObservers: function(prototype) {
  10776.       // called before prototype.observe is chained to inherited object
  10777.       var o = prototype.observe;
  10778.       if (o) {
  10779.         var exploded = {};
  10780.         for (var n in o) {
  10781.           var names = n.split(' ');
  10782.           for (var i=0, ni; ni=names[i]; i++) {
  10783.             exploded[ni] = o[n];
  10784.           }
  10785.         }
  10786.         prototype.observe = exploded;
  10787.       }
  10788.     },
  10789.     optimizePropertyMaps: function(prototype) {
  10790.       if (prototype.observe) {
  10791.         // construct name list
  10792.         var a = prototype._observeNames = [];
  10793.         for (var n in prototype.observe) {
  10794.           var names = n.split(' ');
  10795.           for (var i=0, ni; ni=names[i]; i++) {
  10796.             a.push(ni);
  10797.           }
  10798.         }
  10799.       }
  10800.       if (prototype.publish) {
  10801.         // construct name list
  10802.         var a = prototype._publishNames = [];
  10803.         for (var n in prototype.publish) {
  10804.           a.push(n);
  10805.         }
  10806.       }
  10807.       if (prototype.computed) {
  10808.         // construct name list
  10809.         var a = prototype._computedNames = [];
  10810.         for (var n in prototype.computed) {
  10811.           a.push(n);
  10812.         }
  10813.       }
  10814.     },
  10815.     publishProperties: function(prototype, base) {
  10816.       // if we have any properties to publish
  10817.       var publish = prototype.publish;
  10818.       if (publish) {
  10819.         // transcribe `publish` entries onto own prototype
  10820.         this.requireProperties(publish, prototype, base);
  10821.         // warn and remove accessor names that are broken on some browsers
  10822.         this.filterInvalidAccessorNames(publish);
  10823.         // construct map of lower-cased property names
  10824.         prototype._publishLC = this.lowerCaseMap(publish);
  10825.       }
  10826.       var computed = prototype.computed;
  10827.       if (computed) {
  10828.         // warn and remove accessor names that are broken on some browsers
  10829.         this.filterInvalidAccessorNames(computed);
  10830.       }
  10831.     },
  10832.     // Publishing/computing a property where the name might conflict with a
  10833.     // browser property is not currently supported to help users of Polymer
  10834.     // avoid browser bugs:
  10835.     //
  10836.     // https://code.google.com/p/chromium/issues/detail?id=43394
  10837.     // https://bugs.webkit.org/show_bug.cgi?id=49739
  10838.     //
  10839.     // We can lift this restriction when those bugs are fixed.
  10840.     filterInvalidAccessorNames: function(propertyNames) {
  10841.       for (var name in propertyNames) {
  10842.         // Check if the name is in our blacklist.
  10843.         if (this.propertyNameBlacklist[name]) {
  10844.           console.warn('Cannot define property "' + name + '" for element "' +
  10845.             this.name + '" because it has the same name as an HTMLElement ' +
  10846.             'property, and not all browsers support overriding that. ' +
  10847.             'Consider giving it a different name.');
  10848.           // Remove the invalid accessor from the list.
  10849.           delete propertyNames[name];
  10850.         }
  10851.       }
  10852.     },
  10853.     //
  10854.     // `name: value` entries in the `publish` object may need to generate 
  10855.     // matching properties on the prototype.
  10856.     //
  10857.     // Values that are objects may have a `reflect` property, which
  10858.     // signals that the value describes property control metadata.
  10859.     // In metadata objects, the prototype default value (if any)
  10860.     // is encoded in the `value` property.
  10861.     //
  10862.     // publish: {
  10863.     //   foo: 5, 
  10864.     //   bar: {value: true, reflect: true},
  10865.     //   zot: {}
  10866.     // }
  10867.     //
  10868.     // `reflect` metadata property controls whether changes to the property
  10869.     // are reflected back to the attribute (default false). 
  10870.     //
  10871.     // A value is stored on the prototype unless it's === `undefined`,
  10872.     // in which case the base chain is checked for a value.
  10873.     // If the basal value is also undefined, `null` is stored on the prototype.
  10874.     //
  10875.     // The reflection data is stored on another prototype object, `reflect`
  10876.     // which also can be specified directly.
  10877.     //
  10878.     // reflect: {
  10879.     //   foo: true
  10880.     // }
  10881.     //
  10882.     requireProperties: function(propertyInfos, prototype, base) {
  10883.       // per-prototype storage for reflected properties
  10884.       prototype.reflect = prototype.reflect || {};
  10885.       // ensure a prototype value for each property
  10886.       // and update the property's reflect to attribute status
  10887.       for (var n in propertyInfos) {
  10888.         var value = propertyInfos[n];
  10889.         // value has metadata if it has a `reflect` property
  10890.         if (value && value.reflect !== undefined) {
  10891.           prototype.reflect[n] = Boolean(value.reflect);
  10892.           value = value.value;
  10893.         }
  10894.         // only set a value if one is specified
  10895.         if (value !== undefined) {
  10896.           prototype[n] = value;
  10897.         }
  10898.       }
  10899.     },
  10900.     lowerCaseMap: function(properties) {
  10901.       var map = {};
  10902.       for (var n in properties) {
  10903.         map[n.toLowerCase()] = n;
  10904.       }
  10905.       return map;
  10906.     },
  10907.     createPropertyAccessor: function(name, ignoreWrites) {
  10908.       var proto = this.prototype;
  10909.  
  10910.       var privateName = name + '_';
  10911.       var privateObservable  = name + 'Observable_';
  10912.       proto[privateName] = proto[name];
  10913.  
  10914.       Object.defineProperty(proto, name, {
  10915.         get: function() {
  10916.           var observable = this[privateObservable];
  10917.           if (observable)
  10918.             observable.deliver();
  10919.  
  10920.           return this[privateName];
  10921.         },
  10922.         set: function(value) {
  10923.           if (ignoreWrites) {
  10924.             return this[privateName];
  10925.           }
  10926.  
  10927.           var observable = this[privateObservable];
  10928.           if (observable) {
  10929.             observable.setValue(value);
  10930.             return;
  10931.           }
  10932.  
  10933.           var oldValue = this[privateName];
  10934.           this[privateName] = value;
  10935.           this.emitPropertyChangeRecord(name, value, oldValue);
  10936.  
  10937.           return value;
  10938.         },
  10939.         configurable: true
  10940.       });
  10941.     },
  10942.     createPropertyAccessors: function(prototype) {
  10943.       var n$ = prototype._computedNames;
  10944.       if (n$ && n$.length) {
  10945.         for (var i=0, l=n$.length, n, fn; (i<l) && (n=n$[i]); i++) {
  10946.           this.createPropertyAccessor(n, true);
  10947.         }
  10948.       }
  10949.       var n$ = prototype._publishNames;
  10950.       if (n$ && n$.length) {
  10951.         for (var i=0, l=n$.length, n, fn; (i<l) && (n=n$[i]); i++) {
  10952.           // If the property is computed and published, the accessor is created
  10953.           // above.
  10954.           if (!prototype.computed || !prototype.computed[n]) {
  10955.             this.createPropertyAccessor(n);
  10956.           }
  10957.         }
  10958.       }
  10959.     },
  10960.     // This list contains some property names that people commonly want to use,
  10961.     // but won't work because of Chrome/Safari bugs. It isn't an exhaustive
  10962.     // list. In particular it doesn't contain any property names found on
  10963.     // subtypes of HTMLElement (e.g. name, value). Rather it attempts to catch
  10964.     // some common cases.
  10965.     propertyNameBlacklist: {
  10966.       children: 1,
  10967.       'class': 1,
  10968.       id: 1,
  10969.       hidden: 1,
  10970.       style: 1,
  10971.       title: 1,
  10972.     }
  10973.   };
  10974.  
  10975.   // exports
  10976.  
  10977.   scope.api.declaration.properties = properties;
  10978.  
  10979. })(Polymer);
  10980.  
  10981. (function(scope) {
  10982.  
  10983.   // magic words
  10984.  
  10985.   var ATTRIBUTES_ATTRIBUTE = 'attributes';
  10986.   var ATTRIBUTES_REGEX = /\s|,/;
  10987.  
  10988.   // attributes api
  10989.  
  10990.   var attributes = {
  10991.     
  10992.     inheritAttributesObjects: function(prototype) {
  10993.       // chain our lower-cased publish map to the inherited version
  10994.       this.inheritObject(prototype, 'publishLC');
  10995.       // chain our instance attributes map to the inherited version
  10996.       this.inheritObject(prototype, '_instanceAttributes');
  10997.     },
  10998.  
  10999.     publishAttributes: function(prototype, base) {
  11000.       // merge names from 'attributes' attribute into the 'publish' object
  11001.       var attributes = this.getAttribute(ATTRIBUTES_ATTRIBUTE);
  11002.       if (attributes) {
  11003.         // create a `publish` object if needed.
  11004.         // the `publish` object is only relevant to this prototype, the 
  11005.         // publishing logic in `declaration/properties.js` is responsible for
  11006.         // managing property values on the prototype chain.
  11007.         // TODO(sjmiles): the `publish` object is later chained to it's 
  11008.         //                ancestor object, presumably this is only for 
  11009.         //                reflection or other non-library uses. 
  11010.         var publish = prototype.publish || (prototype.publish = {}); 
  11011.         // names='a b c' or names='a,b,c'
  11012.         var names = attributes.split(ATTRIBUTES_REGEX);
  11013.         // record each name for publishing
  11014.         for (var i=0, l=names.length, n; i<l; i++) {
  11015.           // remove excess ws
  11016.           n = names[i].trim();
  11017.           // looks weird, but causes n to exist on `publish` if it does not;
  11018.           // a more careful test would need expensive `in` operator
  11019.           if (n && publish[n] === undefined) {
  11020.             publish[n] = undefined;
  11021.           }
  11022.         }
  11023.       }
  11024.     },
  11025.  
  11026.     // record clonable attributes from <element>
  11027.     accumulateInstanceAttributes: function() {
  11028.       // inherit instance attributes
  11029.       var clonable = this.prototype._instanceAttributes;
  11030.       // merge attributes from element
  11031.       var a$ = this.attributes;
  11032.       for (var i=0, l=a$.length, a; (i<l) && (a=a$[i]); i++) {  
  11033.         if (this.isInstanceAttribute(a.name)) {
  11034.           clonable[a.name] = a.value;
  11035.         }
  11036.       }
  11037.     },
  11038.  
  11039.     isInstanceAttribute: function(name) {
  11040.       return !this.blackList[name] && name.slice(0,3) !== 'on-';
  11041.     },
  11042.  
  11043.     // do not clone these attributes onto instances
  11044.     blackList: {
  11045.       name: 1,
  11046.       'extends': 1,
  11047.       constructor: 1,
  11048.       noscript: 1,
  11049.       assetpath: 1,
  11050.       'cache-csstext': 1
  11051.     }
  11052.     
  11053.   };
  11054.  
  11055.   // add ATTRIBUTES_ATTRIBUTE to the blacklist
  11056.   attributes.blackList[ATTRIBUTES_ATTRIBUTE] = 1;
  11057.  
  11058.   // exports
  11059.  
  11060.   scope.api.declaration.attributes = attributes;
  11061.  
  11062. })(Polymer);
  11063.  
  11064. (function(scope) {
  11065.  
  11066.   // imports
  11067.   var events = scope.api.declaration.events;
  11068.  
  11069.   var syntax = new PolymerExpressions();
  11070.   var prepareBinding = syntax.prepareBinding;
  11071.  
  11072.   // Polymer takes a first crack at the binding to see if it's a declarative
  11073.   // event handler.
  11074.   syntax.prepareBinding = function(pathString, name, node) {
  11075.     return events.prepareEventBinding(pathString, name, node) ||
  11076.            prepareBinding.call(syntax, pathString, name, node);
  11077.   };
  11078.  
  11079.   // declaration api supporting mdv
  11080.   var mdv = {
  11081.     syntax: syntax,
  11082.     fetchTemplate: function() {
  11083.       return this.querySelector('template');
  11084.     },
  11085.     templateContent: function() {
  11086.       var template = this.fetchTemplate();
  11087.       return template && template.content;
  11088.     },
  11089.     installBindingDelegate: function(template) {
  11090.       if (template) {
  11091.         template.bindingDelegate = this.syntax;
  11092.       }
  11093.     }
  11094.   };
  11095.  
  11096.   // exports
  11097.   scope.api.declaration.mdv = mdv;
  11098.  
  11099. })(Polymer);
  11100.  
  11101. (function(scope) {
  11102.  
  11103.   // imports
  11104.   
  11105.   var api = scope.api;
  11106.   var isBase = scope.isBase;
  11107.   var extend = scope.extend;
  11108.  
  11109.   var hasShadowDOMPolyfill = window.ShadowDOMPolyfill;
  11110.  
  11111.   // prototype api
  11112.  
  11113.   var prototype = {
  11114.  
  11115.     register: function(name, extendeeName) {
  11116.       // build prototype combining extendee, Polymer base, and named api
  11117.       this.buildPrototype(name, extendeeName);
  11118.       // register our custom element with the platform
  11119.       this.registerPrototype(name, extendeeName);
  11120.       // reference constructor in a global named by 'constructor' attribute
  11121.       this.publishConstructor();
  11122.     },
  11123.  
  11124.     buildPrototype: function(name, extendeeName) {
  11125.       // get our custom prototype (before chaining)
  11126.       var extension = scope.getRegisteredPrototype(name);
  11127.       // get basal prototype
  11128.       var base = this.generateBasePrototype(extendeeName);
  11129.       // implement declarative features
  11130.       this.desugarBeforeChaining(extension, base);
  11131.       // join prototypes
  11132.       this.prototype = this.chainPrototypes(extension, base);
  11133.       // more declarative features
  11134.       this.desugarAfterChaining(name, extendeeName);
  11135.     },
  11136.  
  11137.     desugarBeforeChaining: function(prototype, base) {
  11138.       // back reference declaration element
  11139.       // TODO(sjmiles): replace `element` with `elementElement` or `declaration`
  11140.       prototype.element = this;
  11141.       // transcribe `attributes` declarations onto own prototype's `publish`
  11142.       this.publishAttributes(prototype, base);
  11143.       // `publish` properties to the prototype and to attribute watch
  11144.       this.publishProperties(prototype, base);
  11145.       // infer observers for `observe` list based on method names
  11146.       this.inferObservers(prototype);
  11147.       // desugar compound observer syntax, e.g. 'a b c' 
  11148.       this.explodeObservers(prototype);
  11149.     },
  11150.  
  11151.     chainPrototypes: function(prototype, base) {
  11152.       // chain various meta-data objects to inherited versions
  11153.       this.inheritMetaData(prototype, base);
  11154.       // chain custom api to inherited
  11155.       var chained = this.chainObject(prototype, base);
  11156.       // x-platform fixup
  11157.       ensurePrototypeTraversal(chained);
  11158.       return chained;
  11159.     },
  11160.  
  11161.     inheritMetaData: function(prototype, base) {
  11162.       // chain observe object to inherited
  11163.       this.inheritObject('observe', prototype, base);
  11164.       // chain publish object to inherited
  11165.       this.inheritObject('publish', prototype, base);
  11166.       // chain reflect object to inherited
  11167.       this.inheritObject('reflect', prototype, base);
  11168.       // chain our lower-cased publish map to the inherited version
  11169.       this.inheritObject('_publishLC', prototype, base);
  11170.       // chain our instance attributes map to the inherited version
  11171.       this.inheritObject('_instanceAttributes', prototype, base);
  11172.       // chain our event delegates map to the inherited version
  11173.       this.inheritObject('eventDelegates', prototype, base);
  11174.     },
  11175.  
  11176.     // implement various declarative features
  11177.     desugarAfterChaining: function(name, extendee) {
  11178.       // build side-chained lists to optimize iterations
  11179.       this.optimizePropertyMaps(this.prototype);
  11180.       this.createPropertyAccessors(this.prototype);
  11181.       // install mdv delegate on template
  11182.       this.installBindingDelegate(this.fetchTemplate());
  11183.       // install external stylesheets as if they are inline
  11184.       this.installSheets();
  11185.       // adjust any paths in dom from imports
  11186.       this.resolveElementPaths(this);
  11187.       // compile list of attributes to copy to instances
  11188.       this.accumulateInstanceAttributes();
  11189.       // parse on-* delegates declared on `this` element
  11190.       this.parseHostEvents();
  11191.       //
  11192.       // install a helper method this.resolvePath to aid in 
  11193.       // setting resource urls. e.g.
  11194.       // this.$.image.src = this.resolvePath('images/foo.png')
  11195.       this.addResolvePathApi();
  11196.       // under ShadowDOMPolyfill, transforms to approximate missing CSS features
  11197.       if (hasShadowDOMPolyfill) {
  11198.         WebComponents.ShadowCSS.shimStyling(this.templateContent(), name,
  11199.           extendee);
  11200.       }
  11201.       // allow custom element access to the declarative context
  11202.       if (this.prototype.registerCallback) {
  11203.         this.prototype.registerCallback(this);
  11204.       }
  11205.     },
  11206.  
  11207.     // if a named constructor is requested in element, map a reference
  11208.     // to the constructor to the given symbol
  11209.     publishConstructor: function() {
  11210.       var symbol = this.getAttribute('constructor');
  11211.       if (symbol) {
  11212.         window[symbol] = this.ctor;
  11213.       }
  11214.     },
  11215.  
  11216.     // build prototype combining extendee, Polymer base, and named api
  11217.     generateBasePrototype: function(extnds) {
  11218.       var prototype = this.findBasePrototype(extnds);
  11219.       if (!prototype) {
  11220.         // create a prototype based on tag-name extension
  11221.         var prototype = HTMLElement.getPrototypeForTag(extnds);
  11222.         // insert base api in inheritance chain (if needed)
  11223.         prototype = this.ensureBaseApi(prototype);
  11224.         // memoize this base
  11225.         memoizedBases[extnds] = prototype;
  11226.       }
  11227.       return prototype;
  11228.     },
  11229.  
  11230.     findBasePrototype: function(name) {
  11231.       return memoizedBases[name];
  11232.     },
  11233.  
  11234.     // install Polymer instance api into prototype chain, as needed 
  11235.     ensureBaseApi: function(prototype) {
  11236.       if (prototype.PolymerBase) {
  11237.         return prototype;
  11238.       }
  11239.       var extended = Object.create(prototype);
  11240.       // we need a unique copy of base api for each base prototype
  11241.       // therefore we 'extend' here instead of simply chaining
  11242.       api.publish(api.instance, extended);
  11243.       // TODO(sjmiles): sharing methods across prototype chains is
  11244.       // not supported by 'super' implementation which optimizes
  11245.       // by memoizing prototype relationships.
  11246.       // Probably we should have a version of 'extend' that is 
  11247.       // share-aware: it could study the text of each function,
  11248.       // look for usage of 'super', and wrap those functions in
  11249.       // closures.
  11250.       // As of now, there is only one problematic method, so 
  11251.       // we just patch it manually.
  11252.       // To avoid re-entrancy problems, the special super method
  11253.       // installed is called `mixinSuper` and the mixin method
  11254.       // must use this method instead of the default `super`.
  11255.       this.mixinMethod(extended, prototype, api.instance.mdv, 'bind');
  11256.       // return buffed-up prototype
  11257.       return extended;
  11258.     },
  11259.  
  11260.     mixinMethod: function(extended, prototype, api, name) {
  11261.       var $super = function(args) {
  11262.         return prototype[name].apply(this, args);
  11263.       };
  11264.       extended[name] = function() {
  11265.         this.mixinSuper = $super;
  11266.         return api[name].apply(this, arguments);
  11267.       }
  11268.     },
  11269.  
  11270.     // ensure prototype[name] inherits from a prototype.prototype[name]
  11271.     inheritObject: function(name, prototype, base) {
  11272.       // require an object
  11273.       var source = prototype[name] || {};
  11274.       // chain inherited properties onto a new object
  11275.       prototype[name] = this.chainObject(source, base[name]);
  11276.     },
  11277.  
  11278.     // register 'prototype' to custom element 'name', store constructor 
  11279.     registerPrototype: function(name, extendee) { 
  11280.       var info = {
  11281.         prototype: this.prototype
  11282.       }
  11283.       // native element must be specified in extends
  11284.       var typeExtension = this.findTypeExtension(extendee);
  11285.       if (typeExtension) {
  11286.         info.extends = typeExtension;
  11287.       }
  11288.       // register the prototype with HTMLElement for name lookup
  11289.       HTMLElement.register(name, this.prototype);
  11290.       // register the custom type
  11291.       this.ctor = document.registerElement(name, info);
  11292.     },
  11293.  
  11294.     findTypeExtension: function(name) {
  11295.       if (name && name.indexOf('-') < 0) {
  11296.         return name;
  11297.       } else {
  11298.         var p = this.findBasePrototype(name);
  11299.         if (p.element) {
  11300.           return this.findTypeExtension(p.element.extends);
  11301.         }
  11302.       }
  11303.     }
  11304.  
  11305.   };
  11306.  
  11307.   // memoize base prototypes
  11308.   var memoizedBases = {};
  11309.  
  11310.   // implementation of 'chainObject' depends on support for __proto__
  11311.   if (Object.__proto__) {
  11312.     prototype.chainObject = function(object, inherited) {
  11313.       if (object && inherited && object !== inherited) {
  11314.         object.__proto__ = inherited;
  11315.       }
  11316.       return object;
  11317.     }
  11318.   } else {
  11319.     prototype.chainObject = function(object, inherited) {
  11320.       if (object && inherited && object !== inherited) {
  11321.         var chained = Object.create(inherited);
  11322.         object = extend(chained, object);
  11323.       }
  11324.       return object;
  11325.     }
  11326.   }
  11327.  
  11328.   // On platforms that do not support __proto__ (versions of IE), the prototype
  11329.   // chain of a custom element is simulated via installation of __proto__.
  11330.   // Although custom elements manages this, we install it here so it's
  11331.   // available during desugaring.
  11332.   function ensurePrototypeTraversal(prototype) {
  11333.     if (!Object.__proto__) {
  11334.       var ancestor = Object.getPrototypeOf(prototype);
  11335.       prototype.__proto__ = ancestor;
  11336.       if (isBase(ancestor)) {
  11337.         ancestor.__proto__ = Object.getPrototypeOf(ancestor);
  11338.       }
  11339.     }
  11340.   }
  11341.  
  11342.   // exports
  11343.  
  11344.   api.declaration.prototype = prototype;
  11345.  
  11346. })(Polymer);
  11347.  
  11348. (function(scope) {
  11349.  
  11350.   /*
  11351.  
  11352.     Elements are added to a registration queue so that they register in 
  11353.     the proper order at the appropriate time. We do this for a few reasons:
  11354.  
  11355.     * to enable elements to load resources (like stylesheets) 
  11356.     asynchronously. We need to do this until the platform provides an efficient
  11357.     alternative. One issue is that remote @import stylesheets are 
  11358.     re-fetched whenever stamped into a shadowRoot.
  11359.  
  11360.     * to ensure elements loaded 'at the same time' (e.g. via some set of
  11361.     imports) are registered as a batch. This allows elements to be enured from
  11362.     upgrade ordering as long as they query the dom tree 1 task after
  11363.     upgrade (aka domReady). This is a performance tradeoff. On the one hand,
  11364.     elements that could register while imports are loading are prevented from 
  11365.     doing so. On the other, grouping upgrades into a single task means less
  11366.     incremental work (for example style recalcs),  Also, we can ensure the 
  11367.     document is in a known state at the single quantum of time when 
  11368.     elements upgrade.
  11369.  
  11370.   */
  11371.   var queue = {
  11372.  
  11373.     // tell the queue to wait for an element to be ready
  11374.     wait: function(element) {
  11375.       if (!element.__queue) {
  11376.         element.__queue = {};
  11377.         elements.push(element);
  11378.       }
  11379.     },
  11380.  
  11381.     // enqueue an element to the next spot in the queue.
  11382.     enqueue: function(element, check, go) {
  11383.       var shouldAdd = element.__queue && !element.__queue.check;
  11384.       if (shouldAdd) {
  11385.         queueForElement(element).push(element);
  11386.         element.__queue.check = check;
  11387.         element.__queue.go = go;
  11388.       }
  11389.       return (this.indexOf(element) !== 0);
  11390.     },
  11391.  
  11392.     indexOf: function(element) {
  11393.       var i = queueForElement(element).indexOf(element);
  11394.       if (i >= 0 && document.contains(element)) {
  11395.         i += (HTMLImports.useNative || HTMLImports.ready) ? 
  11396.           importQueue.length : 1e9;
  11397.       }
  11398.       return i;  
  11399.     },
  11400.  
  11401.     // tell the queue an element is ready to be registered
  11402.     go: function(element) {
  11403.       var readied = this.remove(element);
  11404.       if (readied) {
  11405.         element.__queue.flushable = true;
  11406.         this.addToFlushQueue(readied);
  11407.         this.check();
  11408.       }
  11409.     },
  11410.  
  11411.     remove: function(element) {
  11412.       var i = this.indexOf(element);
  11413.       if (i !== 0) {
  11414.         //console.warn('queue order wrong', i);
  11415.         return;
  11416.       }
  11417.       return queueForElement(element).shift();
  11418.     },
  11419.  
  11420.     check: function() {
  11421.       // next
  11422.       var element = this.nextElement();
  11423.       if (element) {
  11424.         element.__queue.check.call(element);
  11425.       }
  11426.       if (this.canReady()) {
  11427.         this.ready();
  11428.         return true;
  11429.       }
  11430.     },
  11431.  
  11432.     nextElement: function() {
  11433.       return nextQueued();
  11434.     },
  11435.  
  11436.     canReady: function() {
  11437.       return !this.waitToReady && this.isEmpty();
  11438.     },
  11439.  
  11440.     isEmpty: function() {
  11441.       for (var i=0, l=elements.length, e; (i<l) && 
  11442.           (e=elements[i]); i++) {
  11443.         if (e.__queue && !e.__queue.flushable) {
  11444.           return;
  11445.         }
  11446.       }
  11447.       return true;
  11448.     },
  11449.  
  11450.     addToFlushQueue: function(element) {
  11451.       flushQueue.push(element);  
  11452.     },
  11453.  
  11454.     flush: function() {
  11455.       // prevent re-entrance
  11456.       if (this.flushing) {
  11457.         return;
  11458.       }
  11459.       this.flushing = true;
  11460.       var element;
  11461.       while (flushQueue.length) {
  11462.         element = flushQueue.shift();
  11463.         element.__queue.go.call(element);
  11464.         element.__queue = null;
  11465.       }
  11466.       this.flushing = false;
  11467.     },
  11468.  
  11469.     ready: function() {
  11470.       // TODO(sorvell): As an optimization, turn off CE polyfill upgrading
  11471.       // while registering. This way we avoid having to upgrade each document
  11472.       // piecemeal per registration and can instead register all elements
  11473.       // and upgrade once in a batch. Without this optimization, upgrade time
  11474.       // degrades significantly when SD polyfill is used. This is mainly because
  11475.       // querying the document tree for elements is slow under the SD polyfill.
  11476.       var polyfillWasReady = CustomElements.ready;
  11477.       CustomElements.ready = false;
  11478.       this.flush();
  11479.       if (!CustomElements.useNative) {
  11480.         CustomElements.upgradeDocumentTree(document);
  11481.       }
  11482.       CustomElements.ready = polyfillWasReady;
  11483.       Polymer.flush();
  11484.       requestAnimationFrame(this.flushReadyCallbacks);
  11485.     },
  11486.  
  11487.     addReadyCallback: function(callback) {
  11488.       if (callback) {
  11489.         readyCallbacks.push(callback);
  11490.       }
  11491.     },
  11492.  
  11493.     flushReadyCallbacks: function() {
  11494.       if (readyCallbacks) {
  11495.         var fn;
  11496.         while (readyCallbacks.length) {
  11497.           fn = readyCallbacks.shift();
  11498.           fn();
  11499.         }
  11500.       }
  11501.     },
  11502.   
  11503.     /**
  11504.     Returns a list of elements that have had polymer-elements created but 
  11505.     are not yet ready to register. The list is an array of element definitions.
  11506.     */
  11507.     waitingFor: function() {
  11508.       var e$ = [];
  11509.       for (var i=0, l=elements.length, e; (i<l) && 
  11510.           (e=elements[i]); i++) {
  11511.         if (e.__queue && !e.__queue.flushable) {
  11512.           e$.push(e);
  11513.         }
  11514.       }
  11515.       return e$;
  11516.     },
  11517.  
  11518.     waitToReady: true
  11519.  
  11520.   };
  11521.  
  11522.   var elements = [];
  11523.   var flushQueue = [];
  11524.   var importQueue = [];
  11525.   var mainQueue = [];
  11526.   var readyCallbacks = [];
  11527.  
  11528.   function queueForElement(element) {
  11529.     return document.contains(element) ? mainQueue : importQueue;
  11530.   }
  11531.  
  11532.   function nextQueued() {
  11533.     return importQueue.length ? importQueue[0] : mainQueue[0];
  11534.   }
  11535.  
  11536.   function whenReady(callback) {
  11537.     queue.waitToReady = true;
  11538.     Polymer.endOfMicrotask(function() {
  11539.       HTMLImports.whenReady(function() {
  11540.         queue.addReadyCallback(callback);
  11541.         queue.waitToReady = false;
  11542.         queue.check();
  11543.     });
  11544.     });
  11545.   }
  11546.  
  11547.   /**
  11548.     Forces polymer to register any pending elements. Can be used to abort
  11549.     waiting for elements that are partially defined.
  11550.     @param timeout {Integer} Optional timeout in milliseconds
  11551.   */
  11552.   function forceReady(timeout) {
  11553.     if (timeout === undefined) {
  11554.       queue.ready();
  11555.       return;
  11556.     }
  11557.     var handle = setTimeout(function() {
  11558.       queue.ready();
  11559.     }, timeout);
  11560.     Polymer.whenReady(function() {
  11561.       clearTimeout(handle);
  11562.     });
  11563.   }
  11564.  
  11565.   // exports
  11566.   scope.elements = elements;
  11567.   scope.waitingFor = queue.waitingFor.bind(queue);
  11568.   scope.forceReady = forceReady;
  11569.   scope.queue = queue;
  11570.   scope.whenReady = scope.whenPolymerReady = whenReady;
  11571. })(Polymer);
  11572.  
  11573. (function(scope) {
  11574.  
  11575.   // imports
  11576.  
  11577.   var extend = scope.extend;
  11578.   var api = scope.api;
  11579.   var queue = scope.queue;
  11580.   var whenReady = scope.whenReady;
  11581.   var getRegisteredPrototype = scope.getRegisteredPrototype;
  11582.   var waitingForPrototype = scope.waitingForPrototype;
  11583.  
  11584.   // declarative implementation: <polymer-element>
  11585.  
  11586.   var prototype = extend(Object.create(HTMLElement.prototype), {
  11587.  
  11588.     createdCallback: function() {
  11589.       if (this.getAttribute('name')) {
  11590.         this.init();
  11591.       }
  11592.     },
  11593.  
  11594.     init: function() {
  11595.       // fetch declared values
  11596.       this.name = this.getAttribute('name');
  11597.       this.extends = this.getAttribute('extends');
  11598.       queue.wait(this);
  11599.       // initiate any async resource fetches
  11600.       this.loadResources();
  11601.       // register when all constraints are met
  11602.       this.registerWhenReady();
  11603.     },
  11604.  
  11605.     // TODO(sorvell): we currently queue in the order the prototypes are 
  11606.     // registered, but we should queue in the order that polymer-elements
  11607.     // are registered. We are currently blocked from doing this based on 
  11608.     // crbug.com/395686.
  11609.     registerWhenReady: function() {
  11610.      if (this.registered
  11611.        || this.waitingForPrototype(this.name)
  11612.        || this.waitingForQueue()
  11613.        || this.waitingForResources()) {
  11614.           return;
  11615.       }
  11616.       queue.go(this);
  11617.     },
  11618.  
  11619.     _register: function() {
  11620.       //console.log('registering', this.name);
  11621.       // warn if extending from a custom element not registered via Polymer
  11622.       if (isCustomTag(this.extends) && !isRegistered(this.extends)) {
  11623.         console.warn('%s is attempting to extend %s, an unregistered element ' +
  11624.             'or one that was not registered with Polymer.', this.name,
  11625.             this.extends);
  11626.       }
  11627.       this.register(this.name, this.extends);
  11628.       this.registered = true;
  11629.     },
  11630.  
  11631.     waitingForPrototype: function(name) {
  11632.       if (!getRegisteredPrototype(name)) {
  11633.         // then wait for a prototype
  11634.         waitingForPrototype(name, this);
  11635.         // emulate script if user is not supplying one
  11636.         this.handleNoScript(name);
  11637.         // prototype not ready yet
  11638.         return true;
  11639.       }
  11640.     },
  11641.  
  11642.     handleNoScript: function(name) {
  11643.       // if explicitly marked as 'noscript'
  11644.       if (this.hasAttribute('noscript') && !this.noscript) {
  11645.         this.noscript = true;
  11646.         // imperative element registration
  11647.         Polymer(name);
  11648.       }
  11649.     },
  11650.  
  11651.     waitingForResources: function() {
  11652.       return this._needsResources;
  11653.     },
  11654.  
  11655.     // NOTE: Elements must be queued in proper order for inheritance/composition
  11656.     // dependency resolution. Previously this was enforced for inheritance,
  11657.     // and by rule for composition. It's now entirely by rule.
  11658.     waitingForQueue: function() {
  11659.       return queue.enqueue(this, this.registerWhenReady, this._register);
  11660.     },
  11661.  
  11662.     loadResources: function() {
  11663.       this._needsResources = true;
  11664.       this.loadStyles(function() {
  11665.         this._needsResources = false;
  11666.         this.registerWhenReady();
  11667.       }.bind(this));
  11668.     }
  11669.  
  11670.   });
  11671.  
  11672.   // semi-pluggable APIs 
  11673.  
  11674.   // TODO(sjmiles): should be fully pluggable (aka decoupled, currently
  11675.   // the various plugins are allowed to depend on each other directly)
  11676.   api.publish(api.declaration, prototype);
  11677.  
  11678.   // utility and bookkeeping
  11679.  
  11680.   function isRegistered(name) {
  11681.     return Boolean(HTMLElement.getPrototypeForTag(name));
  11682.   }
  11683.  
  11684.   function isCustomTag(name) {
  11685.     return (name && name.indexOf('-') >= 0);
  11686.   }
  11687.  
  11688.   // boot tasks
  11689.  
  11690.   whenReady(function() {
  11691.     document.body.removeAttribute('unresolved');
  11692.     document.dispatchEvent(
  11693.       new CustomEvent('polymer-ready', {bubbles: true})
  11694.     );
  11695.   });
  11696.  
  11697.   // register polymer-element with document
  11698.  
  11699.   document.registerElement('polymer-element', {prototype: prototype});
  11700.  
  11701. })(Polymer);
  11702.  
  11703. (function(scope) {
  11704.  
  11705. /**
  11706.  * @class Polymer
  11707.  */
  11708.  
  11709. var whenReady = scope.whenReady;
  11710.  
  11711. /**
  11712.  * Loads the set of HTMLImports contained in `node`. Notifies when all
  11713.  * the imports have loaded by calling the `callback` function argument.
  11714.  * This method can be used to lazily load imports. For example, given a 
  11715.  * template:
  11716.  *     
  11717.  *     <template>
  11718.  *       <link rel="import" href="my-import1.html">
  11719.  *       <link rel="import" href="my-import2.html">
  11720.  *     </template>
  11721.  *
  11722.  *     Polymer.importElements(template.content, function() {
  11723.  *       console.log('imports lazily loaded'); 
  11724.  *     });
  11725.  * 
  11726.  * @method importElements
  11727.  * @param {Node} node Node containing the HTMLImports to load.
  11728.  * @param {Function} callback Callback called when all imports have loaded.
  11729.  */
  11730. function importElements(node, callback) {
  11731.   if (node) {
  11732.     document.head.appendChild(node);
  11733.     whenReady(callback);
  11734.   } else if (callback) {
  11735.     callback();
  11736.   }
  11737. }
  11738.  
  11739. /**
  11740.  * Loads an HTMLImport for each url specified in the `urls` array.
  11741.  * Notifies when all the imports have loaded by calling the `callback` 
  11742.  * function argument. This method can be used to lazily load imports. 
  11743.  * For example,
  11744.  *
  11745.  *     Polymer.import(['my-import1.html', 'my-import2.html'], function() {
  11746.  *       console.log('imports lazily loaded'); 
  11747.  *     });
  11748.  * 
  11749.  * @method import
  11750.  * @param {Array} urls Array of urls to load as HTMLImports.
  11751.  * @param {Function} callback Callback called when all imports have loaded.
  11752.  */
  11753. function _import(urls, callback) {
  11754.   if (urls && urls.length) {
  11755.       var frag = document.createDocumentFragment();
  11756.       for (var i=0, l=urls.length, url, link; (i<l) && (url=urls[i]); i++) {
  11757.         link = document.createElement('link');
  11758.         link.rel = 'import';
  11759.         link.href = url;
  11760.         frag.appendChild(link);
  11761.       }
  11762.       importElements(frag, callback);
  11763.   } else if (callback) {
  11764.     callback();
  11765.   }
  11766. }
  11767.  
  11768. // exports
  11769. scope.import = _import;
  11770. scope.importElements = importElements;
  11771.  
  11772. })(Polymer);
  11773.  
  11774. /**
  11775.  * The `auto-binding` element extends the template element. It provides a quick 
  11776.  * and easy way to do data binding without the need to setup a model. 
  11777.  * The `auto-binding` element itself serves as the model and controller for the 
  11778.  * elements it contains. Both data and event handlers can be bound. 
  11779.  *
  11780.  * The `auto-binding` element acts just like a template that is bound to 
  11781.  * a model. It stamps its content in the dom adjacent to itself. When the 
  11782.  * content is stamped, the `template-bound` event is fired.
  11783.  *
  11784.  * Example:
  11785.  *
  11786.  *     <template is="auto-binding">
  11787.  *       <div>Say something: <input value="{{value}}"></div>
  11788.  *       <div>You said: {{value}}</div>
  11789.  *       <button on-tap="{{buttonTap}}">Tap me!</button>
  11790.  *     </template>
  11791.  *     <script>
  11792.  *       var template = document.querySelector('template');
  11793.  *       template.value = 'something';
  11794.  *       template.buttonTap = function() {
  11795.  *         console.log('tap!');
  11796.  *       };
  11797.  *     </script>
  11798.  *
  11799.  * @module Polymer
  11800.  * @status stable
  11801. */
  11802.  
  11803. (function() {
  11804.  
  11805.   var element = document.createElement('polymer-element');
  11806.   element.setAttribute('name', 'auto-binding');
  11807.   element.setAttribute('extends', 'template');
  11808.   element.init();
  11809.  
  11810.   Polymer('auto-binding', {
  11811.  
  11812.     createdCallback: function() {
  11813.       this.syntax = this.bindingDelegate = this.makeSyntax();
  11814.       // delay stamping until polymer-ready so that auto-binding is not
  11815.       // required to load last.
  11816.       Polymer.whenPolymerReady(function() {
  11817.         this.model = this;
  11818.         this.setAttribute('bind', '');
  11819.         // we don't bother with an explicit signal here, we could ust a MO
  11820.         // if necessary
  11821.         this.async(function() {
  11822.           // note: this will marshall *all* the elements in the parentNode
  11823.           // rather than just stamped ones. We'd need to use createInstance
  11824.           // to fix this or something else fancier.
  11825.           this.marshalNodeReferences(this.parentNode);
  11826.           // template stamping is asynchronous so stamping isn't complete
  11827.           // by polymer-ready; fire an event so users can use stamped elements
  11828.           this.fire('template-bound');
  11829.         });
  11830.       }.bind(this));
  11831.     },
  11832.  
  11833.     makeSyntax: function() {
  11834.       var events = Object.create(Polymer.api.declaration.events);
  11835.       var self = this;
  11836.       events.findController = function() { return self.model; };
  11837.  
  11838.       var syntax = new PolymerExpressions();
  11839.       var prepareBinding = syntax.prepareBinding;  
  11840.       syntax.prepareBinding = function(pathString, name, node) {
  11841.         return events.prepareEventBinding(pathString, name, node) ||
  11842.                prepareBinding.call(syntax, pathString, name, node);
  11843.       };
  11844.       return syntax;
  11845.     }
  11846.  
  11847.   });
  11848.  
  11849. })();
  11850.